mirror of https://github.com/python/cpython
bpo-44590: Lazily allocate frame objects (GH-27077)
* Convert "specials" array to InterpreterFrame struct, adding f_lasti, f_state and other non-debug FrameObject fields to it. * Refactor, calls pushing the call to the interpreter upward toward _PyEval_Vector. * Compute f_back when on thread stack, only filling in value when frame object outlives stack invocation. * Move ownership of InterpreterFrame in generator from frame object to generator object. * Do not create frame objects for Python calls. * Do not create frame objects for generators.
This commit is contained in:
parent
0363a4014d
commit
ae0a2b7562
|
@ -19,7 +19,7 @@ PyAPI_FUNC(PyObject *) _PyEval_GetBuiltinId(_Py_Identifier *);
|
|||
flag was set, else return 0. */
|
||||
PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
|
||||
|
||||
PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int exc);
|
||||
PyAPI_FUNC(PyObject *) _PyEval_EvalFrameDefault(PyThreadState *tstate, struct _interpreter_frame *f, int exc);
|
||||
|
||||
PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds);
|
||||
PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void);
|
||||
|
|
|
@ -4,50 +4,17 @@
|
|||
# error "this header file must not be included directly"
|
||||
#endif
|
||||
|
||||
/* These values are chosen so that the inline functions below all
|
||||
* compare f_state to zero.
|
||||
*/
|
||||
enum _framestate {
|
||||
FRAME_CREATED = -2,
|
||||
FRAME_SUSPENDED = -1,
|
||||
FRAME_EXECUTING = 0,
|
||||
FRAME_RETURNED = 1,
|
||||
FRAME_UNWINDING = 2,
|
||||
FRAME_RAISED = 3,
|
||||
FRAME_CLEARED = 4
|
||||
};
|
||||
|
||||
typedef signed char PyFrameState;
|
||||
|
||||
struct _frame {
|
||||
PyObject_HEAD
|
||||
struct _frame *f_back; /* previous frame, or NULL */
|
||||
PyObject **f_valuestack; /* points after the last local */
|
||||
struct _interpreter_frame *f_frame; /* points to the frame data */
|
||||
PyObject *f_trace; /* Trace function */
|
||||
/* Borrowed reference to a generator, or NULL */
|
||||
PyObject *f_gen;
|
||||
int f_stackdepth; /* Depth of value stack */
|
||||
int f_lasti; /* Last instruction if called */
|
||||
int f_lineno; /* Current line number. Only valid if non-zero */
|
||||
PyFrameState f_state; /* What state the frame is in */
|
||||
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 */
|
||||
PyObject **f_localsptr; /* Pointer to locals, cells, free */
|
||||
};
|
||||
|
||||
static inline int _PyFrame_IsRunnable(struct _frame *f) {
|
||||
return f->f_state < FRAME_EXECUTING;
|
||||
}
|
||||
|
||||
static inline int _PyFrame_IsExecuting(struct _frame *f) {
|
||||
return f->f_state == FRAME_EXECUTING;
|
||||
}
|
||||
|
||||
static inline int _PyFrameHasCompleted(struct _frame *f) {
|
||||
return f->f_state > FRAME_EXECUTING;
|
||||
}
|
||||
|
||||
/* Standard object interface */
|
||||
|
||||
PyAPI_DATA(PyTypeObject) PyFrame_Type;
|
||||
|
@ -59,7 +26,7 @@ PyAPI_FUNC(PyFrameObject *) PyFrame_New(PyThreadState *, PyCodeObject *,
|
|||
|
||||
/* only internal use */
|
||||
PyFrameObject*
|
||||
_PyFrame_New_NoTrack(PyThreadState *, PyFrameConstructor *, PyObject *, PyObject **);
|
||||
_PyFrame_New_NoTrack(struct _interpreter_frame *, int);
|
||||
|
||||
|
||||
/* The rest of the interface is specific for frame objects */
|
||||
|
|
|
@ -78,7 +78,7 @@ struct _ts {
|
|||
PyInterpreterState *interp;
|
||||
|
||||
/* Borrowed reference to the current frame (it can be NULL) */
|
||||
PyFrameObject *frame;
|
||||
struct _interpreter_frame *frame;
|
||||
int recursion_depth;
|
||||
int recursion_headroom; /* Allow 50 more calls to handle any errors. */
|
||||
int stackcheck_counter;
|
||||
|
@ -223,7 +223,7 @@ PyAPI_FUNC(void) PyThreadState_DeleteCurrent(void);
|
|||
|
||||
/* Frame evaluation API */
|
||||
|
||||
typedef PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, PyFrameObject *, int);
|
||||
typedef PyObject* (*_PyFrameEvalFunction)(PyThreadState *tstate, struct _interpreter_frame *, int);
|
||||
|
||||
PyAPI_FUNC(_PyFrameEvalFunction) _PyInterpreterState_GetEvalFrameFunc(
|
||||
PyInterpreterState *interp);
|
||||
|
|
|
@ -16,9 +16,9 @@ extern "C" {
|
|||
#define _PyGenObject_HEAD(prefix) \
|
||||
PyObject_HEAD \
|
||||
/* Note: gi_frame can be NULL if the generator is "finished" */ \
|
||||
PyFrameObject *prefix##_frame; \
|
||||
struct _interpreter_frame *prefix##_xframe; \
|
||||
/* The code object backing the generator */ \
|
||||
PyCodeObject *prefix##_code; \
|
||||
PyCodeObject *prefix##_code; \
|
||||
/* List of weak reference. */ \
|
||||
PyObject *prefix##_weakreflist; \
|
||||
/* Name of the generator. */ \
|
||||
|
|
|
@ -41,9 +41,9 @@ extern PyObject *_PyEval_BuiltinsFromGlobals(
|
|||
|
||||
|
||||
static inline PyObject*
|
||||
_PyEval_EvalFrame(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
||||
_PyEval_EvalFrame(PyThreadState *tstate, struct _interpreter_frame *frame, int throwflag)
|
||||
{
|
||||
return tstate->interp->eval_frame(tstate, f, throwflag);
|
||||
return tstate->interp->eval_frame(tstate, frame, throwflag);
|
||||
}
|
||||
|
||||
extern PyObject *
|
||||
|
@ -107,6 +107,9 @@ static inline void _Py_LeaveRecursiveCall_inline(void) {
|
|||
|
||||
#define Py_LeaveRecursiveCall() _Py_LeaveRecursiveCall_inline()
|
||||
|
||||
struct _interpreter_frame *_PyEval_GetFrame(void);
|
||||
|
||||
PyObject *_Py_MakeCoro(PyFrameConstructor *, struct _interpreter_frame *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -4,41 +4,123 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
FRAME_SPECIALS_GLOBALS_OFFSET = 0,
|
||||
FRAME_SPECIALS_BUILTINS_OFFSET = 1,
|
||||
FRAME_SPECIALS_LOCALS_OFFSET = 2,
|
||||
FRAME_SPECIALS_CODE_OFFSET = 3,
|
||||
FRAME_SPECIALS_SIZE = 4
|
||||
/* These values are chosen so that the inline functions below all
|
||||
* compare f_state to zero.
|
||||
*/
|
||||
enum _framestate {
|
||||
FRAME_CREATED = -2,
|
||||
FRAME_SUSPENDED = -1,
|
||||
FRAME_EXECUTING = 0,
|
||||
FRAME_RETURNED = 1,
|
||||
FRAME_UNWINDING = 2,
|
||||
FRAME_RAISED = 3,
|
||||
FRAME_CLEARED = 4
|
||||
};
|
||||
|
||||
static inline PyObject **
|
||||
_PyFrame_Specials(PyFrameObject *f) {
|
||||
return &f->f_valuestack[-FRAME_SPECIALS_SIZE];
|
||||
typedef signed char PyFrameState;
|
||||
|
||||
typedef struct _interpreter_frame {
|
||||
PyObject *f_globals;
|
||||
PyObject *f_builtins;
|
||||
PyObject *f_locals;
|
||||
PyCodeObject *f_code;
|
||||
PyFrameObject *frame_obj;
|
||||
/* Borrowed reference to a generator, or NULL */
|
||||
PyObject *generator;
|
||||
struct _interpreter_frame *previous;
|
||||
int f_lasti; /* Last instruction if called */
|
||||
int stackdepth; /* Depth of value stack */
|
||||
int nlocalsplus;
|
||||
PyFrameState f_state; /* What state the frame is in */
|
||||
PyObject *stack[1];
|
||||
} InterpreterFrame;
|
||||
|
||||
static inline int _PyFrame_IsRunnable(InterpreterFrame *f) {
|
||||
return f->f_state < FRAME_EXECUTING;
|
||||
}
|
||||
|
||||
/* Returns a *borrowed* reference. */
|
||||
static inline PyObject *
|
||||
_PyFrame_GetGlobals(PyFrameObject *f)
|
||||
static inline int _PyFrame_IsExecuting(InterpreterFrame *f) {
|
||||
return f->f_state == FRAME_EXECUTING;
|
||||
}
|
||||
|
||||
static inline int _PyFrameHasCompleted(InterpreterFrame *f) {
|
||||
return f->f_state > FRAME_EXECUTING;
|
||||
}
|
||||
|
||||
#define FRAME_SPECIALS_SIZE ((sizeof(InterpreterFrame)-1)/sizeof(PyObject *))
|
||||
|
||||
InterpreterFrame *
|
||||
_PyInterpreterFrame_HeapAlloc(PyFrameConstructor *con, PyObject *locals);
|
||||
|
||||
static inline void
|
||||
_PyFrame_InitializeSpecials(
|
||||
InterpreterFrame *frame, PyFrameConstructor *con,
|
||||
PyObject *locals, int nlocalsplus)
|
||||
{
|
||||
return _PyFrame_Specials(f)[FRAME_SPECIALS_GLOBALS_OFFSET];
|
||||
frame->f_code = (PyCodeObject *)Py_NewRef(con->fc_code);
|
||||
frame->f_builtins = Py_NewRef(con->fc_builtins);
|
||||
frame->f_globals = Py_NewRef(con->fc_globals);
|
||||
frame->f_locals = Py_XNewRef(locals);
|
||||
frame->nlocalsplus = nlocalsplus;
|
||||
frame->stackdepth = 0;
|
||||
frame->frame_obj = NULL;
|
||||
frame->generator = NULL;
|
||||
frame->f_lasti = -1;
|
||||
frame->f_state = FRAME_CREATED;
|
||||
}
|
||||
|
||||
/* Returns a *borrowed* reference. */
|
||||
static inline PyObject *
|
||||
_PyFrame_GetBuiltins(PyFrameObject *f)
|
||||
/* Gets the pointer to the locals array
|
||||
* that precedes this frame.
|
||||
*/
|
||||
static inline PyObject**
|
||||
_PyFrame_GetLocalsArray(InterpreterFrame *frame)
|
||||
{
|
||||
return _PyFrame_Specials(f)[FRAME_SPECIALS_BUILTINS_OFFSET];
|
||||
return ((PyObject **)frame) - frame->nlocalsplus;
|
||||
}
|
||||
|
||||
/* Returns a *borrowed* reference. */
|
||||
static inline PyCodeObject *
|
||||
_PyFrame_GetCode(PyFrameObject *f)
|
||||
/* For use by _PyFrame_GetFrameObject
|
||||
Do not call directly. */
|
||||
PyFrameObject *
|
||||
_PyFrame_MakeAndSetFrameObject(InterpreterFrame *frame);
|
||||
|
||||
/* Gets the PyFrameObject for this frame, lazily
|
||||
* creating it if necessary.
|
||||
* Returns a borrowed referennce */
|
||||
static inline PyFrameObject *
|
||||
_PyFrame_GetFrameObject(InterpreterFrame *frame)
|
||||
{
|
||||
return (PyCodeObject *)_PyFrame_Specials(f)[FRAME_SPECIALS_CODE_OFFSET];
|
||||
PyFrameObject *res = frame->frame_obj;
|
||||
if (res != NULL) {
|
||||
return res;
|
||||
}
|
||||
return _PyFrame_MakeAndSetFrameObject(frame);
|
||||
}
|
||||
|
||||
int _PyFrame_TakeLocals(PyFrameObject *f);
|
||||
/* Clears all references in the frame.
|
||||
* If take is non-zero, then the InterpreterFrame frame
|
||||
* may be transfered to the frame object it references
|
||||
* instead of being cleared. Either way
|
||||
* the caller no longer owns the references
|
||||
* in the 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);
|
||||
|
||||
int
|
||||
_PyFrame_Traverse(InterpreterFrame *frame, visitproc visit, void *arg);
|
||||
|
||||
int
|
||||
_PyFrame_FastToLocalsWithError(InterpreterFrame *frame);
|
||||
|
||||
void
|
||||
_PyFrame_LocalsToFast(InterpreterFrame *frame, int clear);
|
||||
|
||||
InterpreterFrame *_PyThreadState_PushFrame(
|
||||
PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals);
|
||||
|
||||
void _PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame *frame);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -147,9 +147,6 @@ PyAPI_FUNC(int) _PyState_AddModule(
|
|||
|
||||
PyAPI_FUNC(int) _PyOS_InterruptOccurred(PyThreadState *tstate);
|
||||
|
||||
PyObject **_PyThreadState_PushLocals(PyThreadState *, int size);
|
||||
void _PyThreadState_PopLocals(PyThreadState *, PyObject **);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -56,6 +56,7 @@ def temporary_filename():
|
|||
os_helper.unlink(filename)
|
||||
|
||||
class FaultHandlerTests(unittest.TestCase):
|
||||
|
||||
def get_output(self, code, filename=None, fd=None):
|
||||
"""
|
||||
Run the specified code in Python (in a new child process) and read the
|
||||
|
|
|
@ -1275,7 +1275,7 @@ class SizeofTest(unittest.TestCase):
|
|||
# frame
|
||||
import inspect
|
||||
x = inspect.currentframe()
|
||||
check(x, size('4P3i4cP'))
|
||||
check(x, size('3Pi3c'))
|
||||
# function
|
||||
def func(): pass
|
||||
check(func, size('14Pi'))
|
||||
|
|
|
@ -350,6 +350,7 @@ PYTHON_OBJS= \
|
|||
Python/context.o \
|
||||
Python/dynamic_annotations.o \
|
||||
Python/errors.o \
|
||||
Python/frame.o \
|
||||
Python/frozenmain.o \
|
||||
Python/future.o \
|
||||
Python/getargs.o \
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
All necessary data for executing a Python function (local variables, stack,
|
||||
etc) is now kept in a per-thread stack. Frame objects are lazily allocated
|
||||
on demand. This increases performance by about 7% on the standard benchmark
|
||||
suite. Introspection and debugging are unaffected as frame objects are
|
||||
always available when needed. Patch by Mark Shannon.
|
|
@ -3,7 +3,7 @@
|
|||
#include "pycore_pymem.h" // _Py_tracemalloc_config
|
||||
#include "pycore_traceback.h"
|
||||
#include "pycore_hashtable.h"
|
||||
#include "frameobject.h" // PyFrame_GetBack()
|
||||
#include <pycore_frame.h>
|
||||
|
||||
#include "clinic/_tracemalloc.c.h"
|
||||
/*[clinic input]
|
||||
|
@ -299,18 +299,16 @@ hashtable_compare_traceback(const void *key1, const void *key2)
|
|||
|
||||
|
||||
static void
|
||||
tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
|
||||
tracemalloc_get_frame(InterpreterFrame *pyframe, frame_t *frame)
|
||||
{
|
||||
frame->filename = unknown_filename;
|
||||
int lineno = PyFrame_GetLineNumber(pyframe);
|
||||
int lineno = PyCode_Addr2Line(pyframe->f_code, pyframe->f_lasti*2);
|
||||
if (lineno < 0) {
|
||||
lineno = 0;
|
||||
}
|
||||
frame->lineno = (unsigned int)lineno;
|
||||
|
||||
PyCodeObject *code = PyFrame_GetCode(pyframe);
|
||||
PyObject *filename = code->co_filename;
|
||||
Py_DECREF(code);
|
||||
PyObject *filename = pyframe->f_code->co_filename;
|
||||
|
||||
if (filename == NULL) {
|
||||
#ifdef TRACE_DEBUG
|
||||
|
@ -395,7 +393,7 @@ traceback_get_frames(traceback_t *traceback)
|
|||
return;
|
||||
}
|
||||
|
||||
PyFrameObject *pyframe = PyThreadState_GetFrame(tstate);
|
||||
InterpreterFrame *pyframe = tstate->frame;
|
||||
for (; pyframe != NULL;) {
|
||||
if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
|
||||
tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
|
||||
|
@ -406,8 +404,7 @@ traceback_get_frames(traceback_t *traceback)
|
|||
traceback->total_nframe++;
|
||||
}
|
||||
|
||||
PyFrameObject *back = PyFrame_GetBack(pyframe);
|
||||
Py_DECREF(pyframe);
|
||||
InterpreterFrame *back = pyframe->previous;
|
||||
pyframe = back;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include "Python.h"
|
||||
#include "frameobject.h"
|
||||
#include "pycore_frame.h"
|
||||
#include "interpreteridobject.h"
|
||||
|
||||
|
||||
|
@ -1834,13 +1835,12 @@ _is_running(PyInterpreterState *interp)
|
|||
}
|
||||
|
||||
assert(!PyErr_Occurred());
|
||||
PyFrameObject *frame = PyThreadState_GetFrame(tstate);
|
||||
InterpreterFrame *frame = tstate->frame;
|
||||
if (frame == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int executing = _PyFrame_IsExecuting(frame);
|
||||
Py_DECREF(frame);
|
||||
|
||||
return executing;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "pycore_atomic.h" // _Py_atomic_int
|
||||
#include "pycore_call.h" // _PyObject_Call()
|
||||
#include "pycore_ceval.h" // _PyEval_SignalReceived()
|
||||
#include "pycore_frame.h"
|
||||
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
||||
#include "pycore_pyerrors.h" // _PyErr_SetString()
|
||||
#include "pycore_pylifecycle.h" // NSIG
|
||||
|
@ -1786,11 +1787,7 @@ _PyErr_CheckSignalsTstate(PyThreadState *tstate)
|
|||
*/
|
||||
_Py_atomic_store(&is_tripped, 0);
|
||||
|
||||
PyObject *frame = (PyObject *)tstate->frame;
|
||||
if (!frame) {
|
||||
frame = Py_None;
|
||||
}
|
||||
|
||||
InterpreterFrame *frame = tstate->frame;
|
||||
signal_state_t *state = &signal_global_state;
|
||||
for (int i = 1; i < NSIG; i++) {
|
||||
if (!_Py_atomic_load_relaxed(&Handlers[i].tripped)) {
|
||||
|
@ -1821,8 +1818,16 @@ _PyErr_CheckSignalsTstate(PyThreadState *tstate)
|
|||
PyErr_WriteUnraisable(Py_None);
|
||||
continue;
|
||||
}
|
||||
|
||||
PyObject *arglist = Py_BuildValue("(iO)", i, frame);
|
||||
PyObject *arglist = NULL;
|
||||
if (frame == NULL) {
|
||||
arglist = Py_BuildValue("(iO)", i, Py_None);
|
||||
}
|
||||
else {
|
||||
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
|
||||
if (f != NULL) {
|
||||
arglist = Py_BuildValue("(iO)", i, f);
|
||||
}
|
||||
}
|
||||
PyObject *result;
|
||||
if (arglist) {
|
||||
result = _PyObject_Call(tstate, func, arglist, NULL);
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#define OFF(x) offsetof(PyFrameObject, x)
|
||||
|
||||
static PyMemberDef frame_memberlist[] = {
|
||||
{"f_back", T_OBJECT, OFF(f_back), READONLY},
|
||||
{"f_trace_lines", T_BOOL, OFF(f_trace_lines), 0},
|
||||
{"f_trace_opcodes", T_BOOL, OFF(f_trace_opcodes), 0},
|
||||
{NULL} /* Sentinel */
|
||||
|
@ -33,7 +32,7 @@ frame_getlocals(PyFrameObject *f, void *closure)
|
|||
{
|
||||
if (PyFrame_FastToLocalsWithError(f) < 0)
|
||||
return NULL;
|
||||
PyObject *locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
|
||||
PyObject *locals = f->f_frame->f_locals;
|
||||
Py_INCREF(locals);
|
||||
return locals;
|
||||
}
|
||||
|
@ -46,7 +45,7 @@ PyFrame_GetLineNumber(PyFrameObject *f)
|
|||
return f->f_lineno;
|
||||
}
|
||||
else {
|
||||
return PyCode_Addr2Line(_PyFrame_GetCode(f), f->f_lasti*2);
|
||||
return PyCode_Addr2Line(f->f_frame->f_code, f->f_frame->f_lasti*2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,16 +64,16 @@ frame_getlineno(PyFrameObject *f, void *closure)
|
|||
static PyObject *
|
||||
frame_getlasti(PyFrameObject *f, void *closure)
|
||||
{
|
||||
if (f->f_lasti < 0) {
|
||||
if (f->f_frame->f_lasti < 0) {
|
||||
return PyLong_FromLong(-1);
|
||||
}
|
||||
return PyLong_FromLong(f->f_lasti*2);
|
||||
return PyLong_FromLong(f->f_frame->f_lasti*2);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frame_getglobals(PyFrameObject *f, void *closure)
|
||||
{
|
||||
PyObject *globals = _PyFrame_GetGlobals(f);
|
||||
PyObject *globals = f->f_frame->f_globals;
|
||||
if (globals == NULL) {
|
||||
globals = Py_None;
|
||||
}
|
||||
|
@ -85,7 +84,7 @@ frame_getglobals(PyFrameObject *f, void *closure)
|
|||
static PyObject *
|
||||
frame_getbuiltins(PyFrameObject *f, void *closure)
|
||||
{
|
||||
PyObject *builtins = _PyFrame_GetBuiltins(f);
|
||||
PyObject *builtins = f->f_frame->f_builtins;
|
||||
if (builtins == NULL) {
|
||||
builtins = Py_None;
|
||||
}
|
||||
|
@ -102,6 +101,16 @@ frame_getcode(PyFrameObject *f, void *closure)
|
|||
return (PyObject *)PyFrame_GetCode(f);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frame_getback(PyFrameObject *f, void *closure)
|
||||
{
|
||||
PyObject *res = (PyObject *)PyFrame_GetBack(f);
|
||||
if (res == NULL) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Given the index of the effective opcode,
|
||||
scan back to construct the oparg with EXTENDED_ARG */
|
||||
static unsigned int
|
||||
|
@ -388,9 +397,9 @@ first_line_not_before(int *lines, int len, int line)
|
|||
static void
|
||||
frame_stack_pop(PyFrameObject *f)
|
||||
{
|
||||
assert(f->f_stackdepth > 0);
|
||||
f->f_stackdepth--;
|
||||
PyObject *v = f->f_valuestack[f->f_stackdepth];
|
||||
assert(f->f_frame->stackdepth > 0);
|
||||
f->f_frame->stackdepth--;
|
||||
PyObject *v = f->f_frame->stack[f->f_frame->stackdepth];
|
||||
Py_DECREF(v);
|
||||
}
|
||||
|
||||
|
@ -430,7 +439,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
|
|||
* In addition, jumps are forbidden when not tracing,
|
||||
* as this is a debugging feature.
|
||||
*/
|
||||
switch(f->f_state) {
|
||||
switch(f->f_frame->f_state) {
|
||||
case FRAME_CREATED:
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"can't jump from the 'call' trace event of a new frame");
|
||||
|
@ -472,7 +481,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
|
|||
}
|
||||
new_lineno = (int)l_new_lineno;
|
||||
|
||||
if (new_lineno < _PyFrame_GetCode(f)->co_firstlineno) {
|
||||
if (new_lineno < f->f_frame->f_code->co_firstlineno) {
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"line %d comes before the current code block",
|
||||
new_lineno);
|
||||
|
@ -481,8 +490,8 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
|
|||
|
||||
/* PyCode_NewWithPosOnlyArgs limits co_code to be under INT_MAX so this
|
||||
* should never overflow. */
|
||||
int len = (int)(PyBytes_GET_SIZE(_PyFrame_GetCode(f)->co_code) / sizeof(_Py_CODEUNIT));
|
||||
int *lines = marklines(_PyFrame_GetCode(f), len);
|
||||
int len = (int)(PyBytes_GET_SIZE(f->f_frame->f_code->co_code) / sizeof(_Py_CODEUNIT));
|
||||
int *lines = marklines(f->f_frame->f_code, len);
|
||||
if (lines == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -496,7 +505,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
|
|||
return -1;
|
||||
}
|
||||
|
||||
int64_t *stacks = mark_stacks(_PyFrame_GetCode(f), len);
|
||||
int64_t *stacks = mark_stacks(f->f_frame->f_code, len);
|
||||
if (stacks == NULL) {
|
||||
PyMem_Free(lines);
|
||||
return -1;
|
||||
|
@ -504,7 +513,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
|
|||
|
||||
int64_t best_stack = OVERFLOWED;
|
||||
int best_addr = -1;
|
||||
int64_t start_stack = stacks[f->f_lasti];
|
||||
int64_t start_stack = stacks[f->f_frame->f_lasti];
|
||||
int err = -1;
|
||||
const char *msg = "cannot find bytecode for specified line";
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
@ -538,7 +547,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
|
|||
return -1;
|
||||
}
|
||||
/* Unwind block stack. */
|
||||
if (f->f_state == FRAME_SUSPENDED) {
|
||||
if (f->f_frame->f_state == FRAME_SUSPENDED) {
|
||||
/* Account for value popped by yield */
|
||||
start_stack = pop_value(start_stack);
|
||||
}
|
||||
|
@ -546,9 +555,9 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
|
|||
frame_stack_pop(f);
|
||||
start_stack = pop_value(start_stack);
|
||||
}
|
||||
/* Finally set the new f_lasti and return OK. */
|
||||
/* Finally set the new lasti and return OK. */
|
||||
f->f_lineno = 0;
|
||||
f->f_lasti = best_addr;
|
||||
f->f_frame->f_lasti = best_addr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -579,6 +588,7 @@ frame_settrace(PyFrameObject *f, PyObject* v, void *closure)
|
|||
|
||||
|
||||
static PyGetSetDef frame_getsetlist[] = {
|
||||
{"f_back", (getter)frame_getback, NULL, NULL},
|
||||
{"f_locals", (getter)frame_getlocals, NULL, NULL},
|
||||
{"f_lineno", (getter)frame_getlineno,
|
||||
(setter)frame_setlineno, NULL},
|
||||
|
@ -612,29 +622,27 @@ frame_dealloc(PyFrameObject *f)
|
|||
Py_TRASHCAN_SAFE_BEGIN(f)
|
||||
PyCodeObject *co = NULL;
|
||||
|
||||
/* Kill all local variables including specials. */
|
||||
if (f->f_localsptr) {
|
||||
/* 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;
|
||||
/* Don't clear code object until the end */
|
||||
co = _PyFrame_GetCode(f);
|
||||
PyObject **specials = _PyFrame_Specials(f);
|
||||
Py_CLEAR(specials[FRAME_SPECIALS_GLOBALS_OFFSET]);
|
||||
Py_CLEAR(specials[FRAME_SPECIALS_BUILTINS_OFFSET]);
|
||||
Py_CLEAR(specials[FRAME_SPECIALS_LOCALS_OFFSET]);
|
||||
co = frame->f_code;
|
||||
frame->f_code = NULL;
|
||||
Py_CLEAR(frame->f_globals);
|
||||
Py_CLEAR(frame->f_builtins);
|
||||
Py_CLEAR(frame->f_locals);
|
||||
PyObject **locals = _PyFrame_GetLocalsArray(frame);
|
||||
for (int i = 0; i < co->co_nlocalsplus; i++) {
|
||||
Py_CLEAR(f->f_localsptr[i]);
|
||||
Py_CLEAR(locals[i]);
|
||||
}
|
||||
/* Free items on stack */
|
||||
for (int i = 0; i < f->f_stackdepth; i++) {
|
||||
Py_XDECREF(f->f_valuestack[i]);
|
||||
/* stack */
|
||||
for (int i = 0; i < frame->stackdepth; i++) {
|
||||
Py_CLEAR(frame->stack[i]);
|
||||
}
|
||||
if (f->f_own_locals_memory) {
|
||||
PyMem_Free(f->f_localsptr);
|
||||
f->f_own_locals_memory = 0;
|
||||
}
|
||||
f->f_localsptr = NULL;
|
||||
PyMem_Free(locals);
|
||||
}
|
||||
f->f_stackdepth = 0;
|
||||
Py_XDECREF(f->f_back);
|
||||
Py_CLEAR(f->f_back);
|
||||
Py_CLEAR(f->f_trace);
|
||||
struct _Py_frame_state *state = get_frame_state();
|
||||
#ifdef Py_DEBUG
|
||||
|
@ -654,29 +662,16 @@ frame_dealloc(PyFrameObject *f)
|
|||
Py_TRASHCAN_SAFE_END(f)
|
||||
}
|
||||
|
||||
static inline Py_ssize_t
|
||||
frame_nslots(PyFrameObject *frame)
|
||||
{
|
||||
return frame->f_valuestack - frame->f_localsptr;
|
||||
}
|
||||
|
||||
static int
|
||||
frame_traverse(PyFrameObject *f, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(f->f_back);
|
||||
Py_VISIT(f->f_trace);
|
||||
|
||||
/* locals */
|
||||
PyObject **localsplus = f->f_localsptr;
|
||||
for (Py_ssize_t i = frame_nslots(f); --i >= 0; ++localsplus) {
|
||||
Py_VISIT(*localsplus);
|
||||
if (f->f_own_locals_memory == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* stack */
|
||||
for (int i = 0; i < f->f_stackdepth; i++) {
|
||||
Py_VISIT(f->f_valuestack[i]);
|
||||
}
|
||||
return 0;
|
||||
assert(f->f_frame->frame_obj == NULL);
|
||||
return _PyFrame_Traverse(f->f_frame, visit, arg);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -687,34 +682,35 @@ 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.
|
||||
*/
|
||||
f->f_state = FRAME_CLEARED;
|
||||
f->f_frame->f_state = FRAME_CLEARED;
|
||||
|
||||
Py_CLEAR(f->f_trace);
|
||||
PyCodeObject *co = _PyFrame_GetCode(f);
|
||||
|
||||
/* locals */
|
||||
for (int i = 0; i < co->co_nlocalsplus; i++) {
|
||||
Py_CLEAR(f->f_localsptr[i]);
|
||||
PyObject **locals = _PyFrame_GetLocalsArray(f->f_frame);
|
||||
for (int i = 0; i < f->f_frame->nlocalsplus; i++) {
|
||||
Py_CLEAR(locals[i]);
|
||||
}
|
||||
|
||||
/* stack */
|
||||
for (int i = 0; i < f->f_stackdepth; i++) {
|
||||
Py_CLEAR(f->f_valuestack[i]);
|
||||
for (int i = 0; i < f->f_frame->stackdepth; i++) {
|
||||
Py_CLEAR(f->f_frame->stack[i]);
|
||||
}
|
||||
f->f_stackdepth = 0;
|
||||
f->f_frame->stackdepth = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
|
||||
{
|
||||
if (_PyFrame_IsExecuting(f)) {
|
||||
if (_PyFrame_IsExecuting(f->f_frame)) {
|
||||
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);
|
||||
if (f->f_frame->generator) {
|
||||
_PyGen_Finalize(f->f_frame->generator);
|
||||
assert(f->f_frame->generator == NULL);
|
||||
}
|
||||
(void)frame_tp_clear(f);
|
||||
Py_RETURN_NONE;
|
||||
|
@ -729,7 +725,7 @@ frame_sizeof(PyFrameObject *f, PyObject *Py_UNUSED(ignored))
|
|||
Py_ssize_t res;
|
||||
res = sizeof(PyFrameObject);
|
||||
if (f->f_own_locals_memory) {
|
||||
PyCodeObject *code = _PyFrame_GetCode(f);
|
||||
PyCodeObject *code = f->f_frame->f_code;
|
||||
res += (code->co_nlocalsplus+code->co_stacksize) * sizeof(PyObject *);
|
||||
}
|
||||
return PyLong_FromSsize_t(res);
|
||||
|
@ -742,7 +738,7 @@ static PyObject *
|
|||
frame_repr(PyFrameObject *f)
|
||||
{
|
||||
int lineno = PyFrame_GetLineNumber(f);
|
||||
PyCodeObject *code = _PyFrame_GetCode(f);
|
||||
PyCodeObject *code = f->f_frame->f_code;
|
||||
return PyUnicode_FromFormat(
|
||||
"<frame at %p, file %R, line %d, code %S>",
|
||||
f, code->co_filename, lineno, code->co_name);
|
||||
|
@ -793,33 +789,39 @@ PyTypeObject PyFrame_Type = {
|
|||
|
||||
_Py_IDENTIFIER(__builtins__);
|
||||
|
||||
static inline PyFrameObject*
|
||||
frame_alloc(PyCodeObject *code, PyObject **localsarray)
|
||||
static InterpreterFrame *
|
||||
allocate_heap_frame(PyFrameConstructor *con, PyObject *locals)
|
||||
{
|
||||
int owns;
|
||||
PyFrameObject *f;
|
||||
PyCodeObject *code = (PyCodeObject *)con->fc_code;
|
||||
int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
|
||||
PyObject **localsarray = PyMem_Malloc(sizeof(PyObject *)*size);
|
||||
if (localsarray == NULL) {
|
||||
int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
|
||||
localsarray = PyMem_Malloc(sizeof(PyObject *)*size);
|
||||
if (localsarray == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) {
|
||||
localsarray[i] = NULL;
|
||||
}
|
||||
owns = 1;
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
owns = 0;
|
||||
for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) {
|
||||
localsarray[i] = NULL;
|
||||
}
|
||||
InterpreterFrame *frame = (InterpreterFrame *)(localsarray + code->co_nlocalsplus);
|
||||
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
|
||||
return frame;
|
||||
}
|
||||
|
||||
static inline PyFrameObject*
|
||||
frame_alloc(InterpreterFrame *frame, int owns)
|
||||
{
|
||||
PyFrameObject *f;
|
||||
struct _Py_frame_state *state = get_frame_state();
|
||||
if (state->free_list == NULL)
|
||||
{
|
||||
f = PyObject_GC_New(PyFrameObject, &PyFrame_Type);
|
||||
if (f == NULL) {
|
||||
if (owns) {
|
||||
PyMem_Free(localsarray);
|
||||
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;
|
||||
}
|
||||
|
@ -835,66 +837,23 @@ frame_alloc(PyCodeObject *code, PyObject **localsarray)
|
|||
state->free_list = state->free_list->f_back;
|
||||
_Py_NewReference((PyObject *)f);
|
||||
}
|
||||
f->f_localsptr = localsarray;
|
||||
f->f_frame = frame;
|
||||
f->f_own_locals_memory = owns;
|
||||
return f;
|
||||
}
|
||||
|
||||
int
|
||||
_PyFrame_TakeLocals(PyFrameObject *f)
|
||||
{
|
||||
assert(f->f_own_locals_memory == 0);
|
||||
assert(f->f_stackdepth == 0);
|
||||
Py_ssize_t size = frame_nslots(f);
|
||||
PyObject **copy = PyMem_Malloc(sizeof(PyObject *)*size);
|
||||
if (copy == NULL) {
|
||||
for (int i = 0; i < size; i++) {
|
||||
PyObject *o = f->f_localsptr[i];
|
||||
Py_XDECREF(o);
|
||||
}
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
PyObject *o = f->f_localsptr[i];
|
||||
copy[i] = o;
|
||||
}
|
||||
f->f_own_locals_memory = 1;
|
||||
f->f_localsptr = copy;
|
||||
f->f_valuestack = copy + size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyFrameObject* _Py_HOT_FUNCTION
|
||||
_PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals, PyObject **localsarray)
|
||||
_PyFrame_New_NoTrack(InterpreterFrame *frame, int owns)
|
||||
{
|
||||
assert(con != NULL);
|
||||
assert(con->fc_globals != NULL);
|
||||
assert(con->fc_builtins != NULL);
|
||||
assert(con->fc_code != NULL);
|
||||
assert(locals == NULL || PyMapping_Check(locals));
|
||||
PyCodeObject *code = (PyCodeObject *)con->fc_code;
|
||||
|
||||
PyFrameObject *f = frame_alloc(code, localsarray);
|
||||
PyFrameObject *f = frame_alloc(frame, owns);
|
||||
if (f == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject **specials = f->f_localsptr + code->co_nlocalsplus;
|
||||
f->f_valuestack = specials + FRAME_SPECIALS_SIZE;
|
||||
f->f_back = (PyFrameObject*)Py_XNewRef(tstate->frame);
|
||||
specials[FRAME_SPECIALS_CODE_OFFSET] = Py_NewRef(con->fc_code);
|
||||
specials[FRAME_SPECIALS_BUILTINS_OFFSET] = Py_NewRef(con->fc_builtins);
|
||||
specials[FRAME_SPECIALS_GLOBALS_OFFSET] = Py_NewRef(con->fc_globals);
|
||||
specials[FRAME_SPECIALS_LOCALS_OFFSET] = Py_XNewRef(locals);
|
||||
f->f_back = NULL;
|
||||
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 = 0;
|
||||
f->f_state = FRAME_CREATED;
|
||||
return f;
|
||||
}
|
||||
|
||||
|
@ -917,7 +876,11 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
|
|||
.fc_kwdefaults = NULL,
|
||||
.fc_closure = NULL
|
||||
};
|
||||
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, &desc, locals, NULL);
|
||||
InterpreterFrame *frame = allocate_heap_frame(&desc, locals);
|
||||
if (frame == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyFrameObject *f = _PyFrame_New_NoTrack(frame, 1);
|
||||
if (f) {
|
||||
_PyObject_GC_TRACK(f);
|
||||
}
|
||||
|
@ -925,11 +888,11 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code,
|
|||
}
|
||||
|
||||
static int
|
||||
_PyFrame_OpAlreadyRan(PyFrameObject *f, int opcode, int oparg)
|
||||
_PyFrame_OpAlreadyRan(InterpreterFrame *frame, int opcode, int oparg)
|
||||
{
|
||||
const _Py_CODEUNIT *code =
|
||||
(const _Py_CODEUNIT *)PyBytes_AS_STRING(_PyFrame_GetCode(f)->co_code);
|
||||
for (int i = 0; i < f->f_lasti; i++) {
|
||||
(const _Py_CODEUNIT *)PyBytes_AS_STRING(frame->f_code->co_code);
|
||||
for (int i = 0; i < frame->f_lasti; i++) {
|
||||
if (_Py_OPCODE(code[i]) == opcode && _Py_OPARG(code[i]) == oparg) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -938,25 +901,19 @@ _PyFrame_OpAlreadyRan(PyFrameObject *f, int opcode, int oparg)
|
|||
}
|
||||
|
||||
int
|
||||
PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
||||
{
|
||||
_PyFrame_FastToLocalsWithError(InterpreterFrame *frame) {
|
||||
/* Merge fast locals into f->f_locals */
|
||||
PyObject *locals;
|
||||
PyObject **fast;
|
||||
PyCodeObject *co;
|
||||
|
||||
if (f == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
|
||||
locals = frame->f_locals;
|
||||
if (locals == NULL) {
|
||||
locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET] = PyDict_New();
|
||||
locals = frame->f_locals = PyDict_New();
|
||||
if (locals == NULL)
|
||||
return -1;
|
||||
}
|
||||
co = _PyFrame_GetCode(f);
|
||||
fast = f->f_localsptr;
|
||||
co = frame->f_code;
|
||||
fast = _PyFrame_GetLocalsArray(frame);
|
||||
for (int i = 0; i < co->co_nlocalsplus; i++) {
|
||||
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
|
||||
|
||||
|
@ -974,9 +931,9 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
|||
|
||||
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
|
||||
PyObject *value = fast[i];
|
||||
if (f->f_state != FRAME_CLEARED) {
|
||||
if (frame->f_state != FRAME_CLEARED) {
|
||||
if (kind & CO_FAST_FREE) {
|
||||
// The cell was set by _PyEval_MakeFrameVector() from
|
||||
// The cell was set when the frame was created from
|
||||
// the function's closure.
|
||||
assert(value != NULL && PyCell_Check(value));
|
||||
value = PyCell_GET(value);
|
||||
|
@ -988,12 +945,12 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
|||
// run yet.
|
||||
if (value != NULL) {
|
||||
if (PyCell_Check(value) &&
|
||||
_PyFrame_OpAlreadyRan(f, MAKE_CELL, i)) {
|
||||
_PyFrame_OpAlreadyRan(frame, MAKE_CELL, i)) {
|
||||
// (likely) MAKE_CELL must have executed already.
|
||||
value = PyCell_GET(value);
|
||||
}
|
||||
// (likely) Otherwise it it is an arg (kind & CO_FAST_LOCAL),
|
||||
// with the initial value set by _PyEval_MakeFrameVector()...
|
||||
// with the initial value set when the frame was created...
|
||||
// (unlikely) ...or it was set to some initial value by
|
||||
// an earlier call to PyFrame_LocalsToFast().
|
||||
}
|
||||
|
@ -1021,6 +978,16 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
PyFrame_FastToLocalsWithError(PyFrameObject *f)
|
||||
{
|
||||
if (f == NULL) {
|
||||
PyErr_BadInternalCall();
|
||||
return -1;
|
||||
}
|
||||
return _PyFrame_FastToLocalsWithError(f->f_frame);
|
||||
}
|
||||
|
||||
void
|
||||
PyFrame_FastToLocals(PyFrameObject *f)
|
||||
{
|
||||
|
@ -1034,21 +1001,18 @@ PyFrame_FastToLocals(PyFrameObject *f)
|
|||
}
|
||||
|
||||
void
|
||||
PyFrame_LocalsToFast(PyFrameObject *f, int clear)
|
||||
_PyFrame_LocalsToFast(InterpreterFrame *frame, int clear)
|
||||
{
|
||||
/* Merge locals into fast locals */
|
||||
PyObject *locals;
|
||||
PyObject **fast;
|
||||
PyObject *error_type, *error_value, *error_traceback;
|
||||
PyCodeObject *co;
|
||||
if (f == NULL || f->f_state == FRAME_CLEARED) {
|
||||
return;
|
||||
}
|
||||
locals = _PyFrame_Specials(f)[FRAME_SPECIALS_LOCALS_OFFSET];
|
||||
locals = frame->f_locals;
|
||||
if (locals == NULL)
|
||||
return;
|
||||
fast = f->f_localsptr;
|
||||
co = _PyFrame_GetCode(f);
|
||||
fast = _PyFrame_GetLocalsArray(frame);
|
||||
co = frame->f_code;
|
||||
|
||||
PyErr_Fetch(&error_type, &error_value, &error_traceback);
|
||||
for (int i = 0; i < co->co_nlocalsplus; i++) {
|
||||
|
@ -1070,7 +1034,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
|
|||
PyObject *oldvalue = fast[i];
|
||||
PyObject *cell = NULL;
|
||||
if (kind == CO_FAST_FREE) {
|
||||
// The cell was set by _PyEval_MakeFrameVector() from
|
||||
// The cell was set when the frame was created from
|
||||
// the function's closure.
|
||||
assert(oldvalue != NULL && PyCell_Check(oldvalue));
|
||||
cell = oldvalue;
|
||||
|
@ -1078,7 +1042,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
|
|||
else if (kind & CO_FAST_CELL && oldvalue != NULL) {
|
||||
/* Same test as in PyFrame_FastToLocals() above. */
|
||||
if (PyCell_Check(oldvalue) &&
|
||||
_PyFrame_OpAlreadyRan(f, MAKE_CELL, i)) {
|
||||
_PyFrame_OpAlreadyRan(frame, MAKE_CELL, i)) {
|
||||
// (likely) MAKE_CELL must have executed already.
|
||||
cell = oldvalue;
|
||||
}
|
||||
|
@ -1102,6 +1066,15 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
|
|||
PyErr_Restore(error_type, error_value, error_traceback);
|
||||
}
|
||||
|
||||
void
|
||||
PyFrame_LocalsToFast(PyFrameObject *f, int clear)
|
||||
{
|
||||
if (f == NULL || f->f_frame->f_state == FRAME_CLEARED) {
|
||||
return;
|
||||
}
|
||||
_PyFrame_LocalsToFast(f->f_frame, clear);
|
||||
}
|
||||
|
||||
/* Clear out the free list */
|
||||
void
|
||||
_PyFrame_ClearFreeList(PyInterpreterState *interp)
|
||||
|
@ -1141,7 +1114,7 @@ PyCodeObject *
|
|||
PyFrame_GetCode(PyFrameObject *frame)
|
||||
{
|
||||
assert(frame != NULL);
|
||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||
PyCodeObject *code = frame->f_frame->f_code;
|
||||
assert(code != NULL);
|
||||
Py_INCREF(code);
|
||||
return code;
|
||||
|
@ -1153,6 +1126,9 @@ PyFrame_GetBack(PyFrameObject *frame)
|
|||
{
|
||||
assert(frame != NULL);
|
||||
PyFrameObject *back = frame->f_back;
|
||||
if (back == NULL && frame->f_frame->previous != NULL) {
|
||||
back = _PyFrame_GetFrameObject(frame->f_frame->previous);
|
||||
}
|
||||
Py_XINCREF(back);
|
||||
return back;
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "pycore_pyerrors.h" // _PyErr_ClearExcState()
|
||||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||
#include "frameobject.h"
|
||||
#include "pycore_frame.h"
|
||||
#include "structmember.h" // PyMemberDef
|
||||
#include "opcode.h"
|
||||
|
||||
|
@ -31,10 +32,17 @@ exc_state_traverse(_PyErr_StackItem *exc_state, visitproc visit, void *arg)
|
|||
static int
|
||||
gen_traverse(PyGenObject *gen, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT((PyObject *)gen->gi_frame);
|
||||
Py_VISIT(gen->gi_code);
|
||||
Py_VISIT(gen->gi_name);
|
||||
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);
|
||||
int err = _PyFrame_Traverse(frame, visit, arg);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
/* No need to visit cr_origin, because it's just tuples/str/int, so can't
|
||||
participate in a reference cycle. */
|
||||
return exc_state_traverse(&gen->gi_exc_state, visit, arg);
|
||||
|
@ -47,7 +55,7 @@ _PyGen_Finalize(PyObject *self)
|
|||
PyObject *res = NULL;
|
||||
PyObject *error_type, *error_value, *error_traceback;
|
||||
|
||||
if (gen->gi_frame == NULL || _PyFrameHasCompleted(gen->gi_frame)) {
|
||||
if (gen->gi_xframe == NULL || _PyFrameHasCompleted(gen->gi_xframe)) {
|
||||
/* Generator isn't paused, so no need to close */
|
||||
return;
|
||||
}
|
||||
|
@ -79,7 +87,7 @@ _PyGen_Finalize(PyObject *self)
|
|||
issue a RuntimeWarning. */
|
||||
if (gen->gi_code != NULL &&
|
||||
((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE &&
|
||||
gen->gi_frame->f_lasti == -1)
|
||||
gen->gi_xframe->f_lasti == -1)
|
||||
{
|
||||
_PyErr_WarnUnawaitedCoroutine((PyObject *)gen);
|
||||
}
|
||||
|
@ -122,9 +130,11 @@ gen_dealloc(PyGenObject *gen)
|
|||
and GC_Del. */
|
||||
Py_CLEAR(((PyAsyncGenObject*)gen)->ag_finalizer);
|
||||
}
|
||||
if (gen->gi_frame != NULL) {
|
||||
gen->gi_frame->f_gen = NULL;
|
||||
Py_CLEAR(gen->gi_frame);
|
||||
InterpreterFrame *frame = gen->gi_xframe;
|
||||
if (frame != NULL) {
|
||||
gen->gi_xframe = NULL;
|
||||
frame->previous = NULL;
|
||||
_PyFrame_Clear(frame, 1);
|
||||
}
|
||||
if (((PyCodeObject *)gen->gi_code)->co_flags & CO_COROUTINE) {
|
||||
Py_CLEAR(((PyCoroObject *)gen)->cr_origin);
|
||||
|
@ -141,11 +151,11 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
int exc, int closing)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
PyFrameObject *f = gen->gi_frame;
|
||||
InterpreterFrame *frame = gen->gi_xframe;
|
||||
PyObject *result;
|
||||
|
||||
*presult = NULL;
|
||||
if (f != NULL && _PyFrame_IsExecuting(f)) {
|
||||
if (frame != NULL && _PyFrame_IsExecuting(frame)) {
|
||||
const char *msg = "generator already executing";
|
||||
if (PyCoro_CheckExact(gen)) {
|
||||
msg = "coroutine already executing";
|
||||
|
@ -156,7 +166,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
PyErr_SetString(PyExc_ValueError, msg);
|
||||
return PYGEN_ERROR;
|
||||
}
|
||||
if (f == NULL || _PyFrameHasCompleted(f)) {
|
||||
if (frame == NULL || _PyFrameHasCompleted(frame)) {
|
||||
if (PyCoro_CheckExact(gen) && !closing) {
|
||||
/* `gen` is an exhausted coroutine: raise an error,
|
||||
except when called from gen_close(), which should
|
||||
|
@ -175,19 +185,15 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
return PYGEN_ERROR;
|
||||
}
|
||||
|
||||
assert(_PyFrame_IsRunnable(f));
|
||||
assert(f->f_lasti >= 0 || ((unsigned char *)PyBytes_AS_STRING(gen->gi_code->co_code))[0] == GEN_START);
|
||||
assert(_PyFrame_IsRunnable(frame));
|
||||
assert(frame->f_lasti >= 0 || ((unsigned char *)PyBytes_AS_STRING(gen->gi_code->co_code))[0] == GEN_START);
|
||||
/* Push arg onto the frame's value stack */
|
||||
result = arg ? arg : Py_None;
|
||||
Py_INCREF(result);
|
||||
gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth] = result;
|
||||
gen->gi_frame->f_stackdepth++;
|
||||
frame->stack[frame->stackdepth] = result;
|
||||
frame->stackdepth++;
|
||||
|
||||
/* Generators always return to their most recent caller, not
|
||||
* necessarily their creator. */
|
||||
Py_XINCREF(tstate->frame);
|
||||
assert(f->f_back == NULL);
|
||||
f->f_back = tstate->frame;
|
||||
frame->previous = tstate->frame;
|
||||
|
||||
gen->gi_exc_state.previous_item = tstate->exc_info;
|
||||
tstate->exc_info = &gen->gi_exc_state;
|
||||
|
@ -197,20 +203,20 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
_PyErr_ChainStackItem(NULL);
|
||||
}
|
||||
|
||||
result = _PyEval_EvalFrame(tstate, f, exc);
|
||||
result = _PyEval_EvalFrame(tstate, frame, exc);
|
||||
tstate->exc_info = gen->gi_exc_state.previous_item;
|
||||
gen->gi_exc_state.previous_item = NULL;
|
||||
|
||||
/* Don't keep the reference to f_back any longer than necessary. It
|
||||
assert(tstate->frame == frame->previous);
|
||||
/* Don't keep the reference to previous any longer than necessary. It
|
||||
* may keep a chain of frames alive or it could create a reference
|
||||
* cycle. */
|
||||
assert(f->f_back == tstate->frame);
|
||||
Py_CLEAR(f->f_back);
|
||||
frame->previous = NULL;
|
||||
|
||||
/* If the generator just returned (as opposed to yielding), signal
|
||||
* that the generator is exhausted. */
|
||||
if (result) {
|
||||
if (!_PyFrameHasCompleted(f)) {
|
||||
if (!_PyFrameHasCompleted(frame)) {
|
||||
*presult = result;
|
||||
return PYGEN_NEXT;
|
||||
}
|
||||
|
@ -245,10 +251,10 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
|||
/* generator can't be rerun, so release the frame */
|
||||
/* first clean reference cycle through stored exception traceback */
|
||||
_PyErr_ClearExcState(&gen->gi_exc_state);
|
||||
gen->gi_frame->f_gen = NULL;
|
||||
gen->gi_frame = NULL;
|
||||
Py_DECREF(f);
|
||||
|
||||
frame->generator = NULL;
|
||||
gen->gi_xframe = NULL;
|
||||
_PyFrame_Clear(frame, 1);
|
||||
*presult = result;
|
||||
return result ? PYGEN_RETURN : PYGEN_ERROR;
|
||||
}
|
||||
|
@ -328,13 +334,13 @@ PyObject *
|
|||
_PyGen_yf(PyGenObject *gen)
|
||||
{
|
||||
PyObject *yf = NULL;
|
||||
PyFrameObject *f = gen->gi_frame;
|
||||
|
||||
if (f) {
|
||||
if (gen->gi_xframe) {
|
||||
InterpreterFrame *frame = gen->gi_xframe;
|
||||
PyObject *bytecode = gen->gi_code->co_code;
|
||||
unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode);
|
||||
|
||||
if (f->f_lasti < 0) {
|
||||
if (frame->f_lasti < 0) {
|
||||
/* Return immediately if the frame didn't start yet. YIELD_FROM
|
||||
always come after LOAD_CONST: a code object should not start
|
||||
with YIELD_FROM */
|
||||
|
@ -342,10 +348,10 @@ _PyGen_yf(PyGenObject *gen)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (code[(f->f_lasti+1)*sizeof(_Py_CODEUNIT)] != YIELD_FROM)
|
||||
if (code[(frame->f_lasti+1)*sizeof(_Py_CODEUNIT)] != YIELD_FROM)
|
||||
return NULL;
|
||||
assert(f->f_stackdepth > 0);
|
||||
yf = f->f_valuestack[f->f_stackdepth-1];
|
||||
assert(frame->stackdepth > 0);
|
||||
yf = frame->stack[frame->stackdepth-1];
|
||||
Py_INCREF(yf);
|
||||
}
|
||||
|
||||
|
@ -360,10 +366,10 @@ gen_close(PyGenObject *gen, PyObject *args)
|
|||
int err = 0;
|
||||
|
||||
if (yf) {
|
||||
PyFrameState state = gen->gi_frame->f_state;
|
||||
gen->gi_frame->f_state = FRAME_EXECUTING;
|
||||
PyFrameState state = gen->gi_xframe->f_state;
|
||||
gen->gi_xframe->f_state = FRAME_EXECUTING;
|
||||
err = gen_close_iter(yf);
|
||||
gen->gi_frame->f_state = state;
|
||||
gen->gi_xframe->f_state = state;
|
||||
Py_DECREF(yf);
|
||||
}
|
||||
if (err == 0)
|
||||
|
@ -410,10 +416,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
|
|||
We have to allow some awaits to work it through, hence the
|
||||
`close_on_genexit` parameter here.
|
||||
*/
|
||||
PyFrameState state = gen->gi_frame->f_state;
|
||||
gen->gi_frame->f_state = FRAME_EXECUTING;
|
||||
PyFrameState state = gen->gi_xframe->f_state;
|
||||
gen->gi_xframe->f_state = FRAME_EXECUTING;
|
||||
err = gen_close_iter(yf);
|
||||
gen->gi_frame->f_state = state;
|
||||
gen->gi_xframe->f_state = state;
|
||||
Py_DECREF(yf);
|
||||
if (err < 0)
|
||||
return gen_send_ex(gen, Py_None, 1, 0);
|
||||
|
@ -422,22 +428,26 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
|
|||
if (PyGen_CheckExact(yf) || PyCoro_CheckExact(yf)) {
|
||||
/* `yf` is a generator or a coroutine. */
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
PyFrameObject *f = tstate->frame;
|
||||
InterpreterFrame *frame = gen->gi_xframe;
|
||||
|
||||
|
||||
/* Since we are fast-tracking things by skipping the eval loop,
|
||||
we need to update the current frame so the stack trace
|
||||
will be reported correctly to the user. */
|
||||
/* XXX We should probably be updating the current frame
|
||||
somewhere in ceval.c. */
|
||||
tstate->frame = gen->gi_frame;
|
||||
InterpreterFrame *prev = tstate->frame;
|
||||
frame->previous = prev;
|
||||
tstate->frame = frame;
|
||||
/* Close the generator that we are currently iterating with
|
||||
'yield from' or awaiting on with 'await'. */
|
||||
PyFrameState state = gen->gi_frame->f_state;
|
||||
gen->gi_frame->f_state = FRAME_EXECUTING;
|
||||
PyFrameState state = gen->gi_xframe->f_state;
|
||||
gen->gi_xframe->f_state = FRAME_EXECUTING;
|
||||
ret = _gen_throw((PyGenObject *)yf, close_on_genexit,
|
||||
typ, val, tb);
|
||||
gen->gi_frame->f_state = state;
|
||||
tstate->frame = f;
|
||||
gen->gi_xframe->f_state = state;
|
||||
tstate->frame = prev;
|
||||
frame->previous = NULL;
|
||||
} else {
|
||||
/* `yf` is an iterator or a coroutine-like object. */
|
||||
PyObject *meth;
|
||||
|
@ -449,24 +459,24 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
|
|||
Py_DECREF(yf);
|
||||
goto throw_here;
|
||||
}
|
||||
PyFrameState state = gen->gi_frame->f_state;
|
||||
gen->gi_frame->f_state = FRAME_EXECUTING;
|
||||
PyFrameState state = gen->gi_xframe->f_state;
|
||||
gen->gi_xframe->f_state = FRAME_EXECUTING;
|
||||
ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL);
|
||||
gen->gi_frame->f_state = state;
|
||||
gen->gi_xframe->f_state = state;
|
||||
Py_DECREF(meth);
|
||||
}
|
||||
Py_DECREF(yf);
|
||||
if (!ret) {
|
||||
PyObject *val;
|
||||
/* Pop subiterator from stack */
|
||||
assert(gen->gi_frame->f_stackdepth > 0);
|
||||
gen->gi_frame->f_stackdepth--;
|
||||
ret = gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth];
|
||||
assert(gen->gi_xframe->stackdepth > 0);
|
||||
gen->gi_xframe->stackdepth--;
|
||||
ret = gen->gi_xframe->stack[gen->gi_xframe->stackdepth];
|
||||
assert(ret == yf);
|
||||
Py_DECREF(ret);
|
||||
/* Termination repetition of YIELD_FROM */
|
||||
assert(gen->gi_frame->f_lasti >= 0);
|
||||
gen->gi_frame->f_lasti += 1;
|
||||
assert(gen->gi_xframe->f_lasti >= 0);
|
||||
gen->gi_xframe->f_lasti += 1;
|
||||
if (_PyGen_FetchStopIterationValue(&val) == 0) {
|
||||
ret = gen_send(gen, val);
|
||||
Py_DECREF(val);
|
||||
|
@ -723,10 +733,28 @@ gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored))
|
|||
static PyObject *
|
||||
gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored))
|
||||
{
|
||||
if (gen->gi_frame == NULL) {
|
||||
if (gen->gi_xframe == NULL) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
return PyBool_FromLong(_PyFrame_IsExecuting(gen->gi_frame));
|
||||
return PyBool_FromLong(_PyFrame_IsExecuting(gen->gi_xframe));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
_gen_getframe(PyGenObject *gen, const char *const name)
|
||||
{
|
||||
if (PySys_Audit("object.__getattr__", "Os", gen, name) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (gen->gi_xframe == NULL) {
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(gen->gi_xframe));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
gen_getframe(PyGenObject *gen, void *Py_UNUSED(ignored))
|
||||
{
|
||||
return _gen_getframe(gen, "gi_frame");
|
||||
}
|
||||
|
||||
static PyGetSetDef gen_getsetlist[] = {
|
||||
|
@ -737,11 +765,11 @@ static PyGetSetDef gen_getsetlist[] = {
|
|||
{"gi_yieldfrom", (getter)gen_getyieldfrom, NULL,
|
||||
PyDoc_STR("object being iterated by yield from, or None")},
|
||||
{"gi_running", (getter)gen_getrunning, NULL, NULL},
|
||||
{"gi_frame", (getter)gen_getframe, NULL, NULL},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyMemberDef gen_memberlist[] = {
|
||||
{"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY|PY_AUDIT_READ},
|
||||
{"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY|PY_AUDIT_READ},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
@ -814,6 +842,84 @@ PyTypeObject PyGen_Type = {
|
|||
_PyGen_Finalize, /* tp_finalize */
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
make_gen(PyTypeObject *type, PyFrameConstructor *con, InterpreterFrame *frame)
|
||||
{
|
||||
PyGenObject *gen = PyObject_GC_New(PyGenObject, type);
|
||||
if (gen == NULL) {
|
||||
assert(frame->frame_obj == NULL);
|
||||
_PyFrame_Clear(frame, 1);
|
||||
return NULL;
|
||||
}
|
||||
gen->gi_xframe = frame;
|
||||
frame->generator = (PyObject *)gen;
|
||||
gen->gi_code = frame->f_code;
|
||||
Py_INCREF(gen->gi_code);
|
||||
gen->gi_weakreflist = NULL;
|
||||
gen->gi_exc_state.exc_type = NULL;
|
||||
gen->gi_exc_state.exc_value = NULL;
|
||||
gen->gi_exc_state.exc_traceback = NULL;
|
||||
gen->gi_exc_state.previous_item = NULL;
|
||||
if (con->fc_name != NULL)
|
||||
gen->gi_name = con->fc_name;
|
||||
else
|
||||
gen->gi_name = gen->gi_code->co_name;
|
||||
Py_INCREF(gen->gi_name);
|
||||
if (con->fc_qualname != NULL)
|
||||
gen->gi_qualname = con->fc_qualname;
|
||||
else
|
||||
gen->gi_qualname = gen->gi_name;
|
||||
Py_INCREF(gen->gi_qualname);
|
||||
_PyObject_GC_TRACK(gen);
|
||||
return (PyObject *)gen;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
compute_cr_origin(int origin_depth);
|
||||
|
||||
PyObject *
|
||||
_Py_MakeCoro(PyFrameConstructor *con, InterpreterFrame *frame)
|
||||
{
|
||||
int coro_flags = ((PyCodeObject *)con->fc_code)->co_flags &
|
||||
(CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
|
||||
assert(coro_flags);
|
||||
if (coro_flags == CO_GENERATOR) {
|
||||
return make_gen(&PyGen_Type, con, frame);
|
||||
}
|
||||
if (coro_flags == CO_ASYNC_GENERATOR) {
|
||||
PyAsyncGenObject *o;
|
||||
o = (PyAsyncGenObject *)make_gen(&PyAsyncGen_Type, con, frame);
|
||||
if (o == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
o->ag_finalizer = NULL;
|
||||
o->ag_closed = 0;
|
||||
o->ag_hooks_inited = 0;
|
||||
o->ag_running_async = 0;
|
||||
return (PyObject*)o;
|
||||
}
|
||||
assert (coro_flags == CO_COROUTINE);
|
||||
PyObject *coro = make_gen(&PyCoro_Type, con, frame);
|
||||
if (!coro) {
|
||||
return NULL;
|
||||
}
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
int origin_depth = tstate->coroutine_origin_tracking_depth;
|
||||
|
||||
if (origin_depth == 0) {
|
||||
((PyCoroObject *)coro)->cr_origin = NULL;
|
||||
} else {
|
||||
PyObject *cr_origin = compute_cr_origin(origin_depth);
|
||||
((PyCoroObject *)coro)->cr_origin = cr_origin;
|
||||
if (!cr_origin) {
|
||||
Py_DECREF(coro);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return coro;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
|
||||
PyObject *name, PyObject *qualname)
|
||||
|
@ -823,8 +929,16 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f,
|
|||
Py_DECREF(f);
|
||||
return NULL;
|
||||
}
|
||||
gen->gi_frame = f;
|
||||
f->f_gen = (PyObject *) gen;
|
||||
|
||||
/* Take ownership of the frame */
|
||||
assert(f->f_frame->frame_obj == NULL);
|
||||
assert(f->f_own_locals_memory);
|
||||
gen->gi_xframe = f->f_frame;
|
||||
gen->gi_xframe->frame_obj = f;
|
||||
f->f_own_locals_memory = 0;
|
||||
gen->gi_xframe->generator = (PyObject *) gen;
|
||||
assert(PyObject_GC_IsTracked((PyObject *)f));
|
||||
|
||||
gen->gi_code = PyFrame_GetCode(f);
|
||||
gen->gi_weakreflist = NULL;
|
||||
gen->gi_exc_state.exc_type = NULL;
|
||||
|
@ -958,12 +1072,19 @@ coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored))
|
|||
static PyObject *
|
||||
cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored))
|
||||
{
|
||||
if (coro->cr_frame == NULL) {
|
||||
if (coro->cr_xframe == NULL) {
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
return PyBool_FromLong(_PyFrame_IsExecuting(coro->cr_frame));
|
||||
return PyBool_FromLong(_PyFrame_IsExecuting(coro->cr_xframe));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
cr_getframe(PyCoroObject *coro, void *Py_UNUSED(ignored))
|
||||
{
|
||||
return _gen_getframe((PyGenObject *)coro, "cr_frame");
|
||||
}
|
||||
|
||||
|
||||
static PyGetSetDef coro_getsetlist[] = {
|
||||
{"__name__", (getter)gen_get_name, (setter)gen_set_name,
|
||||
PyDoc_STR("name of the coroutine")},
|
||||
|
@ -972,11 +1093,11 @@ static PyGetSetDef coro_getsetlist[] = {
|
|||
{"cr_await", (getter)coro_get_cr_await, NULL,
|
||||
PyDoc_STR("object being awaited on, or None")},
|
||||
{"cr_running", (getter)cr_getrunning, NULL, NULL},
|
||||
{"cr_frame", (getter)cr_getframe, NULL, NULL},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyMemberDef coro_memberlist[] = {
|
||||
{"cr_frame", T_OBJECT, offsetof(PyCoroObject, cr_frame), READONLY|PY_AUDIT_READ},
|
||||
{"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY|PY_AUDIT_READ},
|
||||
{"cr_origin", T_OBJECT, offsetof(PyCoroObject, cr_origin), READONLY},
|
||||
{NULL} /* Sentinel */
|
||||
|
@ -1150,11 +1271,11 @@ PyTypeObject _PyCoroWrapper_Type = {
|
|||
static PyObject *
|
||||
compute_cr_origin(int origin_depth)
|
||||
{
|
||||
PyFrameObject *frame = PyEval_GetFrame();
|
||||
InterpreterFrame *frame = _PyEval_GetFrame();
|
||||
/* First count how many frames we have */
|
||||
int frame_count = 0;
|
||||
for (; frame && frame_count < origin_depth; ++frame_count) {
|
||||
frame = frame->f_back;
|
||||
frame = frame->previous;
|
||||
}
|
||||
|
||||
/* Now collect them */
|
||||
|
@ -1162,20 +1283,19 @@ compute_cr_origin(int origin_depth)
|
|||
if (cr_origin == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
frame = PyEval_GetFrame();
|
||||
frame = _PyEval_GetFrame();
|
||||
for (int i = 0; i < frame_count; ++i) {
|
||||
PyCodeObject *code = PyFrame_GetCode(frame);
|
||||
PyCodeObject *code = frame->f_code;
|
||||
PyObject *frameinfo = Py_BuildValue("OiO",
|
||||
code->co_filename,
|
||||
PyFrame_GetLineNumber(frame),
|
||||
PyCode_Addr2Line(frame->f_code, frame->f_lasti*2),
|
||||
code->co_name);
|
||||
Py_DECREF(code);
|
||||
if (!frameinfo) {
|
||||
Py_DECREF(cr_origin);
|
||||
return NULL;
|
||||
}
|
||||
PyTuple_SET_ITEM(cr_origin, i, frameinfo);
|
||||
frame = frame->f_back;
|
||||
frame = frame->previous;
|
||||
}
|
||||
|
||||
return cr_origin;
|
||||
|
@ -1346,6 +1466,11 @@ async_gen_athrow(PyAsyncGenObject *o, PyObject *args)
|
|||
return async_gen_athrow_new(o, args);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
ag_getframe(PyAsyncGenObject *ag, void *Py_UNUSED(ignored))
|
||||
{
|
||||
return _gen_getframe((PyGenObject *)ag, "ag_frame");
|
||||
}
|
||||
|
||||
static PyGetSetDef async_gen_getsetlist[] = {
|
||||
{"__name__", (getter)gen_get_name, (setter)gen_set_name,
|
||||
|
@ -1354,11 +1479,11 @@ static PyGetSetDef async_gen_getsetlist[] = {
|
|||
PyDoc_STR("qualified name of the async generator")},
|
||||
{"ag_await", (getter)coro_get_cr_await, NULL,
|
||||
PyDoc_STR("object being awaited on, or None")},
|
||||
{"ag_frame", (getter)ag_getframe, NULL, NULL},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static PyMemberDef async_gen_memberlist[] = {
|
||||
{"ag_frame", T_OBJECT, offsetof(PyAsyncGenObject, ag_frame), READONLY|PY_AUDIT_READ},
|
||||
{"ag_running", T_BOOL, offsetof(PyAsyncGenObject, ag_running_async),
|
||||
READONLY},
|
||||
{"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), READONLY|PY_AUDIT_READ},
|
||||
|
@ -1865,7 +1990,7 @@ static PyObject *
|
|||
async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
|
||||
{
|
||||
PyGenObject *gen = (PyGenObject*)o->agt_gen;
|
||||
PyFrameObject *f = gen->gi_frame;
|
||||
InterpreterFrame *frame = gen->gi_xframe;
|
||||
PyObject *retval;
|
||||
|
||||
if (o->agt_state == AWAITABLE_STATE_CLOSED) {
|
||||
|
@ -1875,7 +2000,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
if (f == NULL || _PyFrameHasCompleted(f)) {
|
||||
if (frame == NULL || _PyFrameHasCompleted(frame)) {
|
||||
o->agt_state = AWAITABLE_STATE_CLOSED;
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "pycore_pystate.h" // _PyThreadState_GET()
|
||||
#include "pycore_unionobject.h" // _Py_union_type_or
|
||||
#include "frameobject.h"
|
||||
#include "pycore_frame.h"
|
||||
#include "opcode.h" // MAKE_CELL
|
||||
#include "structmember.h" // PyMemberDef
|
||||
|
||||
|
@ -8867,12 +8868,13 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
|
|||
return -1;
|
||||
}
|
||||
|
||||
PyObject *firstarg = f->f_localsptr[0];
|
||||
assert(f->f_frame->nlocalsplus > 0);
|
||||
PyObject *firstarg = _PyFrame_GetLocalsArray(f->f_frame)[0];
|
||||
// The first argument might be a cell.
|
||||
if (firstarg != NULL && (_PyLocals_GetKind(co->co_localspluskinds, 0) & CO_FAST_CELL)) {
|
||||
// "firstarg" is a cell here unless (very unlikely) super()
|
||||
// was called from the C-API before the first MAKE_CELL op.
|
||||
if (f->f_lasti >= 0) {
|
||||
if (f->f_frame->f_lasti >= 0) {
|
||||
assert(_Py_OPCODE(*co->co_firstinstr) == MAKE_CELL);
|
||||
assert(PyCell_Check(firstarg));
|
||||
firstarg = PyCell_GET(firstarg);
|
||||
|
@ -8892,7 +8894,7 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
|
|||
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
|
||||
assert(PyUnicode_Check(name));
|
||||
if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) {
|
||||
PyObject *cell = f->f_localsptr[i];
|
||||
PyObject *cell = _PyFrame_GetLocalsArray(f->f_frame)[i];
|
||||
if (cell == NULL || !PyCell_Check(cell)) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"super(): bad __class__ cell");
|
||||
|
|
|
@ -456,6 +456,7 @@
|
|||
<ClCompile Include="..\Python\errors.c" />
|
||||
<ClCompile Include="..\Python\fileutils.c" />
|
||||
<ClCompile Include="..\Python\formatter_unicode.c" />
|
||||
<ClCompile Include="..\Python\frame.c" />
|
||||
<ClCompile Include="..\Python\frozen.c" />
|
||||
<ClCompile Include="..\Python\future.c" />
|
||||
<ClCompile Include="..\Python\getargs.c" />
|
||||
|
|
|
@ -854,10 +854,8 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno,
|
|||
*lineno = 1;
|
||||
}
|
||||
else {
|
||||
globals = _PyFrame_GetGlobals(f);
|
||||
PyCodeObject *code = PyFrame_GetCode(f);
|
||||
*filename = code->co_filename;
|
||||
Py_DECREF(code);
|
||||
globals = f->f_frame->f_globals;
|
||||
*filename = f->f_frame->f_code->co_filename;
|
||||
Py_INCREF(*filename);
|
||||
*lineno = PyFrame_GetLineNumber(f);
|
||||
Py_DECREF(f);
|
||||
|
|
433
Python/ceval.c
433
Python/ceval.c
|
@ -62,27 +62,27 @@ static int lltrace;
|
|||
static int prtrace(PyThreadState *, PyObject *, const char *);
|
||||
#endif
|
||||
static int call_trace(Py_tracefunc, PyObject *,
|
||||
PyThreadState *, PyFrameObject *,
|
||||
PyThreadState *, InterpreterFrame *,
|
||||
int, PyObject *);
|
||||
static int call_trace_protected(Py_tracefunc, PyObject *,
|
||||
PyThreadState *, PyFrameObject *,
|
||||
PyThreadState *, InterpreterFrame *,
|
||||
int, PyObject *);
|
||||
static void call_exc_trace(Py_tracefunc, PyObject *,
|
||||
PyThreadState *, PyFrameObject *);
|
||||
PyThreadState *, InterpreterFrame *);
|
||||
static int maybe_call_line_trace(Py_tracefunc, PyObject *,
|
||||
PyThreadState *, PyFrameObject *, int);
|
||||
static void maybe_dtrace_line(PyFrameObject *, PyTraceInfo *, int);
|
||||
static void dtrace_function_entry(PyFrameObject *);
|
||||
static void dtrace_function_return(PyFrameObject *);
|
||||
PyThreadState *, InterpreterFrame *, int);
|
||||
static void maybe_dtrace_line(InterpreterFrame *, PyTraceInfo *, int);
|
||||
static void dtrace_function_entry(InterpreterFrame *);
|
||||
static void dtrace_function_return(InterpreterFrame *);
|
||||
|
||||
static PyObject * import_name(PyThreadState *, PyFrameObject *,
|
||||
static PyObject * import_name(PyThreadState *, InterpreterFrame *,
|
||||
PyObject *, PyObject *, PyObject *);
|
||||
static PyObject * import_from(PyThreadState *, PyObject *, PyObject *);
|
||||
static int import_all_from(PyThreadState *, PyObject *, PyObject *);
|
||||
static void format_exc_check_arg(PyThreadState *, PyObject *, const char *, PyObject *);
|
||||
static void format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg);
|
||||
static PyObject * unicode_concatenate(PyThreadState *, PyObject *, PyObject *,
|
||||
PyFrameObject *, const _Py_CODEUNIT *);
|
||||
InterpreterFrame *, const _Py_CODEUNIT *);
|
||||
static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg);
|
||||
static void format_kwargs_error(PyThreadState *, PyObject *func, PyObject *kwargs);
|
||||
static void format_awaitable_error(PyThreadState *, PyTypeObject *, int, int);
|
||||
|
@ -1065,14 +1065,14 @@ PyEval_EvalFrame(PyFrameObject *f)
|
|||
{
|
||||
/* Function kept for backward compatibility */
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
return _PyEval_EvalFrame(tstate, f, 0);
|
||||
return _PyEval_EvalFrame(tstate, f->f_frame, 0);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
return _PyEval_EvalFrame(tstate, f, throwflag);
|
||||
return _PyEval_EvalFrame(tstate, f->f_frame, throwflag);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1231,7 +1231,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
|
|||
if (cframe.use_tracing OR_DTRACE_LINE OR_LLTRACE) { \
|
||||
goto tracing_dispatch; \
|
||||
} \
|
||||
f->f_lasti = INSTR_OFFSET(); \
|
||||
frame->f_lasti = INSTR_OFFSET(); \
|
||||
NEXTOPARG(); \
|
||||
DISPATCH_GOTO(); \
|
||||
}
|
||||
|
@ -1320,7 +1320,7 @@ eval_frame_handle_pending(PyThreadState *tstate)
|
|||
|
||||
/* The stack can grow at most MAXINT deep, as co_nlocals and
|
||||
co_stacksize are ints. */
|
||||
#define STACK_LEVEL() ((int)(stack_pointer - f->f_valuestack))
|
||||
#define STACK_LEVEL() ((int)(stack_pointer - frame->stack))
|
||||
#define EMPTY() (STACK_LEVEL() == 0)
|
||||
#define TOP() (stack_pointer[-1])
|
||||
#define SECOND() (stack_pointer[-2])
|
||||
|
@ -1388,12 +1388,12 @@ eval_frame_handle_pending(PyThreadState *tstate)
|
|||
|
||||
#define UPDATE_PREV_INSTR_OPARG(instr, oparg) ((uint8_t*)(instr))[-1] = (oparg)
|
||||
|
||||
#define GLOBALS() specials[FRAME_SPECIALS_GLOBALS_OFFSET]
|
||||
#define BUILTINS() specials[FRAME_SPECIALS_BUILTINS_OFFSET]
|
||||
#define LOCALS() specials[FRAME_SPECIALS_LOCALS_OFFSET]
|
||||
#define GLOBALS() frame->f_globals
|
||||
#define BUILTINS() frame->f_builtins
|
||||
#define LOCALS() frame->f_locals
|
||||
|
||||
PyObject* _Py_HOT_FUNCTION
|
||||
_PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
||||
_PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag)
|
||||
{
|
||||
_Py_EnsureTstateNotNULL(tstate);
|
||||
|
||||
|
@ -1409,7 +1409,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
_Py_CODEUNIT *next_instr;
|
||||
int opcode; /* Current opcode */
|
||||
int oparg; /* Current opcode argument, if any */
|
||||
PyObject **localsplus, **specials;
|
||||
PyObject **localsplus;
|
||||
PyObject *retval = NULL; /* Return value */
|
||||
_Py_atomic_int * const eval_breaker = &tstate->interp->ceval.eval_breaker;
|
||||
PyCodeObject *co;
|
||||
|
@ -1438,9 +1438,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
tstate->cframe = &cframe;
|
||||
|
||||
/* push frame */
|
||||
tstate->frame = f;
|
||||
specials = f->f_valuestack - FRAME_SPECIALS_SIZE;
|
||||
co = (PyCodeObject *)specials[FRAME_SPECIALS_CODE_OFFSET];
|
||||
tstate->frame = frame;
|
||||
co = frame->f_code;
|
||||
|
||||
if (cframe.use_tracing) {
|
||||
if (tstate->c_tracefunc != NULL) {
|
||||
|
@ -1459,7 +1458,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
whenever an exception is detected. */
|
||||
if (call_trace_protected(tstate->c_tracefunc,
|
||||
tstate->c_traceobj,
|
||||
tstate, f,
|
||||
tstate, frame,
|
||||
PyTrace_CALL, Py_None)) {
|
||||
/* Trace function raised an error */
|
||||
goto exit_eval_frame;
|
||||
|
@ -1470,7 +1469,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
return itself and isn't called for "line" events */
|
||||
if (call_trace_protected(tstate->c_profilefunc,
|
||||
tstate->c_profileobj,
|
||||
tstate, f,
|
||||
tstate, frame,
|
||||
PyTrace_CALL, Py_None)) {
|
||||
/* Profile function raised an error */
|
||||
goto exit_eval_frame;
|
||||
|
@ -1479,7 +1478,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
}
|
||||
|
||||
if (PyDTrace_FUNCTION_ENTRY_ENABLED())
|
||||
dtrace_function_entry(f);
|
||||
dtrace_function_entry(frame);
|
||||
|
||||
/* Increment the warmup counter and quicken if warm enough
|
||||
* _Py_Quicken is idempotent so we don't worry about overflow */
|
||||
|
@ -1495,34 +1494,34 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
|
||||
names = co->co_names;
|
||||
consts = co->co_consts;
|
||||
localsplus = f->f_localsptr;
|
||||
localsplus = _PyFrame_GetLocalsArray(frame);
|
||||
first_instr = co->co_firstinstr;
|
||||
/*
|
||||
f->f_lasti refers to the index of the last instruction,
|
||||
frame->f_lasti refers to the index of the last instruction,
|
||||
unless it's -1 in which case next_instr should be first_instr.
|
||||
|
||||
YIELD_FROM sets f_lasti to itself, in order to repeatedly yield
|
||||
YIELD_FROM sets frame->f_lasti to itself, in order to repeatedly yield
|
||||
multiple values.
|
||||
|
||||
When the PREDICT() macros are enabled, some opcode pairs follow in
|
||||
direct succession without updating f->f_lasti. A successful
|
||||
direct succession without updating frame->f_lasti. A successful
|
||||
prediction effectively links the two codes together as if they
|
||||
were a single new opcode; accordingly,f->f_lasti will point to
|
||||
were a single new opcode; accordingly,frame->f_lasti will point to
|
||||
the first code in the pair (for instance, GET_ITER followed by
|
||||
FOR_ITER is effectively a single opcode and f->f_lasti will point
|
||||
FOR_ITER is effectively a single opcode and frame->f_lasti will point
|
||||
to the beginning of the combined pair.)
|
||||
*/
|
||||
assert(f->f_lasti >= -1);
|
||||
next_instr = first_instr + f->f_lasti + 1;
|
||||
stack_pointer = f->f_valuestack + f->f_stackdepth;
|
||||
/* Set f->f_stackdepth to -1.
|
||||
assert(frame->f_lasti >= -1);
|
||||
next_instr = first_instr + frame->f_lasti + 1;
|
||||
stack_pointer = frame->stack + frame->stackdepth;
|
||||
/* Set stackdepth to -1.
|
||||
* Update when returning or calling trace function.
|
||||
Having f_stackdepth <= 0 ensures that invalid
|
||||
values are not visible to the cycle GC.
|
||||
We choose -1 rather than 0 to assist debugging.
|
||||
*/
|
||||
f->f_stackdepth = -1;
|
||||
f->f_state = FRAME_EXECUTING;
|
||||
frame->stackdepth = -1;
|
||||
frame->f_state = FRAME_EXECUTING;
|
||||
|
||||
#ifdef LLTRACE
|
||||
{
|
||||
|
@ -1546,7 +1545,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
#endif
|
||||
|
||||
for (;;) {
|
||||
assert(stack_pointer >= f->f_valuestack); /* else underflow */
|
||||
assert(STACK_LEVEL() >= 0); /* else underflow */
|
||||
assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */
|
||||
assert(!_PyErr_Occurred(tstate));
|
||||
|
||||
|
@ -1586,12 +1585,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
|
||||
tracing_dispatch:
|
||||
{
|
||||
int instr_prev = f->f_lasti;
|
||||
f->f_lasti = INSTR_OFFSET();
|
||||
int instr_prev = frame->f_lasti;
|
||||
frame->f_lasti = INSTR_OFFSET();
|
||||
TRACING_NEXTOPARG();
|
||||
|
||||
if (PyDTrace_LINE_ENABLED())
|
||||
maybe_dtrace_line(f, &tstate->trace_info, instr_prev);
|
||||
maybe_dtrace_line(frame, &tstate->trace_info, instr_prev);
|
||||
|
||||
/* line-by-line tracing support */
|
||||
|
||||
|
@ -1600,19 +1599,19 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
int err;
|
||||
/* see maybe_call_line_trace()
|
||||
for expository comments */
|
||||
f->f_stackdepth = (int)(stack_pointer - f->f_valuestack);
|
||||
frame->stackdepth = (int)(stack_pointer - frame->stack);
|
||||
|
||||
err = maybe_call_line_trace(tstate->c_tracefunc,
|
||||
tstate->c_traceobj,
|
||||
tstate, f, instr_prev);
|
||||
tstate, frame, instr_prev);
|
||||
if (err) {
|
||||
/* trace function raised an exception */
|
||||
goto error;
|
||||
}
|
||||
/* Reload possibly changed frame fields */
|
||||
JUMPTO(f->f_lasti);
|
||||
stack_pointer = f->f_valuestack+f->f_stackdepth;
|
||||
f->f_stackdepth = -1;
|
||||
JUMPTO(frame->f_lasti);
|
||||
stack_pointer = frame->stack+frame->stackdepth;
|
||||
frame->stackdepth = -1;
|
||||
TRACING_NEXTOPARG();
|
||||
}
|
||||
}
|
||||
|
@ -1623,11 +1622,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
if (lltrace) {
|
||||
if (HAS_ARG(opcode)) {
|
||||
printf("%d: %d, %d\n",
|
||||
f->f_lasti, opcode, oparg);
|
||||
frame->f_lasti, opcode, oparg);
|
||||
}
|
||||
else {
|
||||
printf("%d: %d\n",
|
||||
f->f_lasti, opcode);
|
||||
frame->f_lasti, opcode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -1876,7 +1875,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
speedup on microbenchmarks. */
|
||||
if (PyUnicode_CheckExact(left) &&
|
||||
PyUnicode_CheckExact(right)) {
|
||||
sum = unicode_concatenate(tstate, left, right, f, next_instr);
|
||||
sum = unicode_concatenate(tstate, left, right, frame, next_instr);
|
||||
/* unicode_concatenate consumed the ref to left */
|
||||
}
|
||||
else {
|
||||
|
@ -2162,7 +2161,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
PyObject *left = TOP();
|
||||
PyObject *sum;
|
||||
if (PyUnicode_CheckExact(left) && PyUnicode_CheckExact(right)) {
|
||||
sum = unicode_concatenate(tstate, left, right, f, next_instr);
|
||||
sum = unicode_concatenate(tstate, left, right, frame, next_instr);
|
||||
/* unicode_concatenate consumed the ref to left */
|
||||
}
|
||||
else {
|
||||
|
@ -2322,8 +2321,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
case TARGET(RETURN_VALUE): {
|
||||
retval = POP();
|
||||
assert(EMPTY());
|
||||
f->f_state = FRAME_RETURNED;
|
||||
f->f_stackdepth = 0;
|
||||
frame->f_state = FRAME_RETURNED;
|
||||
frame->stackdepth = 0;
|
||||
goto exiting;
|
||||
}
|
||||
|
||||
|
@ -2480,7 +2479,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
if (retval == NULL) {
|
||||
if (tstate->c_tracefunc != NULL
|
||||
&& _PyErr_ExceptionMatches(tstate, PyExc_StopIteration))
|
||||
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f);
|
||||
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
|
||||
if (_PyGen_FetchStopIterationValue(&retval) == 0) {
|
||||
gen_status = PYGEN_RETURN;
|
||||
}
|
||||
|
@ -2508,10 +2507,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
assert (gen_status == PYGEN_NEXT);
|
||||
/* receiver remains on stack, retval is value to be yielded */
|
||||
/* and repeat... */
|
||||
assert(f->f_lasti > 0);
|
||||
f->f_lasti -= 1;
|
||||
f->f_state = FRAME_SUSPENDED;
|
||||
f->f_stackdepth = (int)(stack_pointer - f->f_valuestack);
|
||||
assert(frame->f_lasti > 0);
|
||||
frame->f_lasti -= 1;
|
||||
frame->f_state = FRAME_SUSPENDED;
|
||||
frame->stackdepth = (int)(stack_pointer - frame->stack);
|
||||
goto exiting;
|
||||
}
|
||||
|
||||
|
@ -2527,8 +2526,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
}
|
||||
retval = w;
|
||||
}
|
||||
f->f_state = FRAME_SUSPENDED;
|
||||
f->f_stackdepth = (int)(stack_pointer - f->f_valuestack);
|
||||
frame->f_state = FRAME_SUSPENDED;
|
||||
frame->stackdepth = (int)(stack_pointer - frame->stack);
|
||||
goto exiting;
|
||||
}
|
||||
|
||||
|
@ -2575,7 +2574,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
case TARGET(POP_EXCEPT_AND_RERAISE): {
|
||||
PyObject *lasti = PEEK(4);
|
||||
if (PyLong_Check(lasti)) {
|
||||
f->f_lasti = PyLong_AsLong(lasti);
|
||||
frame->f_lasti = PyLong_AsLong(lasti);
|
||||
assert(!_PyErr_Occurred(tstate));
|
||||
}
|
||||
else {
|
||||
|
@ -2606,7 +2605,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
if (oparg) {
|
||||
PyObject *lasti = PEEK(oparg+3);
|
||||
if (PyLong_Check(lasti)) {
|
||||
f->f_lasti = PyLong_AsLong(lasti);
|
||||
frame->f_lasti = PyLong_AsLong(lasti);
|
||||
assert(!_PyErr_Occurred(tstate));
|
||||
}
|
||||
else {
|
||||
|
@ -3579,7 +3578,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
PyObject *fromlist = POP();
|
||||
PyObject *level = TOP();
|
||||
PyObject *res;
|
||||
res = import_name(tstate, f, name, fromlist, level);
|
||||
res = import_name(tstate, frame, name, fromlist, level);
|
||||
Py_DECREF(level);
|
||||
Py_DECREF(fromlist);
|
||||
SET_TOP(res);
|
||||
|
@ -3591,7 +3590,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
case TARGET(IMPORT_STAR): {
|
||||
PyObject *from = POP(), *locals;
|
||||
int err;
|
||||
if (PyFrame_FastToLocalsWithError(f) < 0) {
|
||||
if (_PyFrame_FastToLocalsWithError(frame) < 0) {
|
||||
Py_DECREF(from);
|
||||
goto error;
|
||||
}
|
||||
|
@ -3604,7 +3603,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
goto error;
|
||||
}
|
||||
err = import_all_from(tstate, locals, from);
|
||||
PyFrame_LocalsToFast(f, 0);
|
||||
_PyFrame_LocalsToFast(frame, 0);
|
||||
Py_DECREF(from);
|
||||
if (err != 0)
|
||||
goto error;
|
||||
|
@ -3918,7 +3917,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
goto error;
|
||||
}
|
||||
else if (tstate->c_tracefunc != NULL) {
|
||||
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, f);
|
||||
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
|
||||
}
|
||||
_PyErr_Clear(tstate);
|
||||
}
|
||||
|
@ -4381,7 +4380,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
|
|||
default:
|
||||
fprintf(stderr,
|
||||
"XXX lineno: %d, opcode: %d\n",
|
||||
PyFrame_GetLineNumber(f),
|
||||
PyCode_Addr2Line(frame->f_code, frame->f_lasti*2),
|
||||
opcode);
|
||||
_PyErr_SetString(tstate, PyExc_SystemError, "unknown opcode");
|
||||
goto error;
|
||||
|
@ -4450,19 +4449,22 @@ error:
|
|||
#endif
|
||||
|
||||
/* Log traceback info. */
|
||||
PyTraceBack_Here(f);
|
||||
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
|
||||
if (f != NULL) {
|
||||
PyTraceBack_Here(f);
|
||||
}
|
||||
|
||||
if (tstate->c_tracefunc != NULL) {
|
||||
/* Make sure state is set to FRAME_EXECUTING for tracing */
|
||||
assert(f->f_state == FRAME_EXECUTING);
|
||||
f->f_state = FRAME_UNWINDING;
|
||||
assert(frame->f_state == FRAME_EXECUTING);
|
||||
frame->f_state = FRAME_UNWINDING;
|
||||
call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj,
|
||||
tstate, f);
|
||||
tstate, frame);
|
||||
}
|
||||
|
||||
exception_unwind:
|
||||
f->f_state = FRAME_UNWINDING;
|
||||
/* We can't use f->f_lasti here, as RERAISE may have set it */
|
||||
frame->f_state = FRAME_UNWINDING;
|
||||
/* We can't use frame->f_lasti here, as RERAISE may have set it */
|
||||
int offset = INSTR_OFFSET()-1;
|
||||
int level, handler, lasti;
|
||||
if (get_exception_handler(co, offset, &level, &handler, &lasti) == 0) {
|
||||
|
@ -4477,7 +4479,7 @@ exception_unwind:
|
|||
}
|
||||
PyObject *exc, *val, *tb;
|
||||
if (lasti) {
|
||||
PyObject *lasti = PyLong_FromLong(f->f_lasti);
|
||||
PyObject *lasti = PyLong_FromLong(frame->f_lasti);
|
||||
if (lasti == NULL) {
|
||||
goto exception_unwind;
|
||||
}
|
||||
|
@ -4502,8 +4504,8 @@ exception_unwind:
|
|||
PUSH(exc);
|
||||
JUMPTO(handler);
|
||||
/* Resume normal execution */
|
||||
f->f_state = FRAME_EXECUTING;
|
||||
f->f_lasti = handler;
|
||||
frame->f_state = FRAME_EXECUTING;
|
||||
frame->f_lasti = handler;
|
||||
NEXTOPARG();
|
||||
goto dispatch_opcode;
|
||||
} /* main loop */
|
||||
|
@ -4516,19 +4518,19 @@ exception_unwind:
|
|||
PyObject *o = POP();
|
||||
Py_XDECREF(o);
|
||||
}
|
||||
f->f_stackdepth = 0;
|
||||
f->f_state = FRAME_RAISED;
|
||||
frame->stackdepth = 0;
|
||||
frame->f_state = FRAME_RAISED;
|
||||
exiting:
|
||||
if (cframe.use_tracing) {
|
||||
if (tstate->c_tracefunc) {
|
||||
if (call_trace_protected(tstate->c_tracefunc, tstate->c_traceobj,
|
||||
tstate, f, PyTrace_RETURN, retval)) {
|
||||
tstate, frame, PyTrace_RETURN, retval)) {
|
||||
Py_CLEAR(retval);
|
||||
}
|
||||
}
|
||||
if (tstate->c_profilefunc) {
|
||||
if (call_trace_protected(tstate->c_profilefunc, tstate->c_profileobj,
|
||||
tstate, f, PyTrace_RETURN, retval)) {
|
||||
tstate, frame, PyTrace_RETURN, retval)) {
|
||||
Py_CLEAR(retval);
|
||||
}
|
||||
}
|
||||
|
@ -4541,10 +4543,9 @@ exit_eval_frame:
|
|||
tstate->cframe->use_tracing = cframe.use_tracing;
|
||||
|
||||
if (PyDTrace_FUNCTION_RETURN_ENABLED())
|
||||
dtrace_function_return(f);
|
||||
dtrace_function_return(frame);
|
||||
_Py_LeaveRecursiveCall(tstate);
|
||||
tstate->frame = f->f_back;
|
||||
|
||||
tstate->frame = frame->previous;
|
||||
return _Py_CheckFunctionResult(tstate, NULL, retval, __func__);
|
||||
}
|
||||
|
||||
|
@ -5051,116 +5052,110 @@ fail: /* Jump here from prelude on failure */
|
|||
|
||||
}
|
||||
|
||||
|
||||
PyFrameObject *
|
||||
_PyEval_MakeFrameVector(PyThreadState *tstate,
|
||||
static InterpreterFrame *
|
||||
make_coro_frame(PyThreadState *tstate,
|
||||
PyFrameConstructor *con, PyObject *locals,
|
||||
PyObject *const *args, Py_ssize_t argcount,
|
||||
PyObject *kwnames, PyObject** localsarray)
|
||||
PyObject *kwnames)
|
||||
{
|
||||
assert(is_tstate_valid(tstate));
|
||||
assert(con->fc_defaults == NULL || PyTuple_CheckExact(con->fc_defaults));
|
||||
|
||||
/* Create the frame */
|
||||
PyFrameObject *f = _PyFrame_New_NoTrack(tstate, con, locals, localsarray);
|
||||
if (f == NULL) {
|
||||
PyCodeObject *code = (PyCodeObject *)con->fc_code;
|
||||
int size = code->co_nlocalsplus+code->co_stacksize + FRAME_SPECIALS_SIZE;
|
||||
PyObject **localsarray = PyMem_Malloc(sizeof(PyObject *)*size);
|
||||
if (localsarray == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
if (initialize_locals(tstate, con, f->f_localsptr, args, argcount, kwnames)) {
|
||||
Py_DECREF(f);
|
||||
for (Py_ssize_t i=0; i < code->co_nlocalsplus; i++) {
|
||||
localsarray[i] = NULL;
|
||||
}
|
||||
InterpreterFrame *frame = (InterpreterFrame *)(localsarray + code->co_nlocalsplus);
|
||||
_PyFrame_InitializeSpecials(frame, con, locals, code->co_nlocalsplus);
|
||||
assert(frame->frame_obj == NULL);
|
||||
if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames)) {
|
||||
_PyFrame_Clear(frame, 1);
|
||||
return NULL;
|
||||
}
|
||||
return f;
|
||||
return frame;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
make_coro(PyFrameConstructor *con, PyFrameObject *f)
|
||||
make_coro(PyThreadState *tstate, PyFrameConstructor *con,
|
||||
PyObject *locals,
|
||||
PyObject* const* args, size_t argcount,
|
||||
PyObject *kwnames)
|
||||
{
|
||||
assert (((PyCodeObject *)con->fc_code)->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR));
|
||||
PyObject *gen;
|
||||
int is_coro = ((PyCodeObject *)con->fc_code)->co_flags & CO_COROUTINE;
|
||||
|
||||
/* Don't need to keep the reference to f_back, it will be set
|
||||
* when the generator is resumed. */
|
||||
Py_CLEAR(f->f_back);
|
||||
|
||||
/* Create a new generator that owns the ready to run frame
|
||||
* and return that as the value. */
|
||||
if (is_coro) {
|
||||
gen = PyCoro_New(f, con->fc_name, con->fc_qualname);
|
||||
} else if (((PyCodeObject *)con->fc_code)->co_flags & CO_ASYNC_GENERATOR) {
|
||||
gen = PyAsyncGen_New(f, con->fc_name, con->fc_qualname);
|
||||
} else {
|
||||
gen = PyGen_NewWithQualName(f, con->fc_name, con->fc_qualname);
|
||||
InterpreterFrame *frame = make_coro_frame(tstate, con, locals, args, argcount, kwnames);
|
||||
if (frame == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *gen = _Py_MakeCoro(con, frame);
|
||||
if (gen == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_PyObject_GC_TRACK(f);
|
||||
|
||||
return gen;
|
||||
}
|
||||
|
||||
static InterpreterFrame *
|
||||
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con,
|
||||
PyObject *locals, PyObject* const* args,
|
||||
size_t argcount, PyObject *kwnames)
|
||||
{
|
||||
InterpreterFrame * frame = _PyThreadState_PushFrame(tstate, con, locals);
|
||||
if (frame == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject **localsarray = _PyFrame_GetLocalsArray(frame);
|
||||
if (initialize_locals(tstate, con, localsarray, args, argcount, kwnames)) {
|
||||
_PyFrame_Clear(frame, 0);
|
||||
return NULL;
|
||||
}
|
||||
frame->previous = tstate->frame;
|
||||
tstate->frame = frame;
|
||||
return frame;
|
||||
}
|
||||
|
||||
static int
|
||||
_PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame)
|
||||
{
|
||||
++tstate->recursion_depth;
|
||||
assert(frame->frame_obj == NULL || frame->frame_obj->f_own_locals_memory == 0);
|
||||
if (_PyFrame_Clear(frame, 0)) {
|
||||
return -1;
|
||||
}
|
||||
assert(frame->frame_obj == NULL);
|
||||
--tstate->recursion_depth;
|
||||
tstate->frame = frame->previous;
|
||||
_PyThreadState_PopFrame(tstate, frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyEval_Vector(PyThreadState *tstate, PyFrameConstructor *con,
|
||||
PyObject *locals,
|
||||
PyObject* const* args, size_t argcount,
|
||||
PyObject *kwnames)
|
||||
{
|
||||
PyObject **localsarray;
|
||||
PyCodeObject *code = (PyCodeObject *)con->fc_code;
|
||||
int is_coro = code->co_flags &
|
||||
(CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR);
|
||||
if (is_coro) {
|
||||
localsarray = NULL;
|
||||
return make_coro(tstate, con, locals, args, argcount, kwnames);
|
||||
}
|
||||
else {
|
||||
int size = code->co_nlocalsplus + code->co_stacksize +
|
||||
FRAME_SPECIALS_SIZE;
|
||||
localsarray = _PyThreadState_PushLocals(tstate, size);
|
||||
if (localsarray == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
PyFrameObject *f = _PyEval_MakeFrameVector(
|
||||
tstate, con, locals, args, argcount, kwnames, localsarray);
|
||||
if (f == NULL) {
|
||||
if (!is_coro) {
|
||||
_PyThreadState_PopLocals(tstate, localsarray);
|
||||
}
|
||||
InterpreterFrame *frame = _PyEvalFramePushAndInit(
|
||||
tstate, con, locals, args, argcount, kwnames);
|
||||
if (frame == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (is_coro) {
|
||||
return make_coro(con, f);
|
||||
assert (tstate->interp->eval_frame != NULL);
|
||||
PyObject *retval = _PyEval_EvalFrame(tstate, frame, 0);
|
||||
assert(frame->stackdepth == 0);
|
||||
if (_PyEvalFrameClearAndPop(tstate, frame)) {
|
||||
retval = NULL;
|
||||
}
|
||||
PyObject *retval = _PyEval_EvalFrame(tstate, f, 0);
|
||||
assert(f->f_stackdepth == 0);
|
||||
|
||||
/* decref'ing the frame can cause __del__ methods to get invoked,
|
||||
which can call back into Python. While we're done with the
|
||||
current Python frame (f), the associated C stack is still in use,
|
||||
so recursion_depth must be boosted for the duration.
|
||||
*/
|
||||
assert (!is_coro);
|
||||
assert(f->f_own_locals_memory == 0);
|
||||
if (Py_REFCNT(f) > 1) {
|
||||
Py_DECREF(f);
|
||||
_PyObject_GC_TRACK(f);
|
||||
if (_PyFrame_TakeLocals(f)) {
|
||||
Py_CLEAR(retval);
|
||||
}
|
||||
}
|
||||
else {
|
||||
++tstate->recursion_depth;
|
||||
f->f_localsptr = NULL;
|
||||
for (int i = 0; i < code->co_nlocalsplus + FRAME_SPECIALS_SIZE; i++) {
|
||||
Py_XDECREF(localsarray[i]);
|
||||
}
|
||||
Py_DECREF(f);
|
||||
--tstate->recursion_depth;
|
||||
}
|
||||
_PyThreadState_PopLocals(tstate, localsarray);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -5467,7 +5462,7 @@ prtrace(PyThreadState *tstate, PyObject *v, const char *str)
|
|||
static void
|
||||
call_exc_trace(Py_tracefunc func, PyObject *self,
|
||||
PyThreadState *tstate,
|
||||
PyFrameObject *f)
|
||||
InterpreterFrame *f)
|
||||
{
|
||||
PyObject *type, *value, *traceback, *orig_traceback, *arg;
|
||||
int err;
|
||||
|
@ -5497,7 +5492,7 @@ call_exc_trace(Py_tracefunc func, PyObject *self,
|
|||
|
||||
static int
|
||||
call_trace_protected(Py_tracefunc func, PyObject *obj,
|
||||
PyThreadState *tstate, PyFrameObject *frame,
|
||||
PyThreadState *tstate, InterpreterFrame *frame,
|
||||
int what, PyObject *arg)
|
||||
{
|
||||
PyObject *type, *value, *traceback;
|
||||
|
@ -5518,9 +5513,9 @@ call_trace_protected(Py_tracefunc func, PyObject *obj,
|
|||
}
|
||||
|
||||
static void
|
||||
initialize_trace_info(PyTraceInfo *trace_info, PyFrameObject *frame)
|
||||
initialize_trace_info(PyTraceInfo *trace_info, InterpreterFrame *frame)
|
||||
{
|
||||
PyCodeObject *code = _PyFrame_GetCode(frame);
|
||||
PyCodeObject *code = frame->f_code;
|
||||
if (trace_info->code != code) {
|
||||
trace_info->code = code;
|
||||
_PyCode_InitAddressRange(code, &trace_info->bounds);
|
||||
|
@ -5529,7 +5524,7 @@ initialize_trace_info(PyTraceInfo *trace_info, PyFrameObject *frame)
|
|||
|
||||
static int
|
||||
call_trace(Py_tracefunc func, PyObject *obj,
|
||||
PyThreadState *tstate, PyFrameObject *frame,
|
||||
PyThreadState *tstate, InterpreterFrame *frame,
|
||||
int what, PyObject *arg)
|
||||
{
|
||||
int result;
|
||||
|
@ -5537,15 +5532,19 @@ call_trace(Py_tracefunc func, PyObject *obj,
|
|||
return 0;
|
||||
tstate->tracing++;
|
||||
tstate->cframe->use_tracing = 0;
|
||||
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
|
||||
if (f == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (frame->f_lasti < 0) {
|
||||
frame->f_lineno = _PyFrame_GetCode(frame)->co_firstlineno;
|
||||
f->f_lineno = frame->f_code->co_firstlineno;
|
||||
}
|
||||
else {
|
||||
initialize_trace_info(&tstate->trace_info, frame);
|
||||
frame->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti*2, &tstate->trace_info.bounds);
|
||||
f->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti*2, &tstate->trace_info.bounds);
|
||||
}
|
||||
result = func(obj, frame, what, arg);
|
||||
frame->f_lineno = 0;
|
||||
result = func(obj, f, what, arg);
|
||||
f->f_lineno = 0;
|
||||
tstate->cframe->use_tracing = ((tstate->c_tracefunc != NULL)
|
||||
|| (tstate->c_profilefunc != NULL));
|
||||
tstate->tracing--;
|
||||
|
@ -5572,7 +5571,7 @@ _PyEval_CallTracing(PyObject *func, PyObject *args)
|
|||
/* See Objects/lnotab_notes.txt for a description of how tracing works. */
|
||||
static int
|
||||
maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
|
||||
PyThreadState *tstate, PyFrameObject *frame, int instr_prev)
|
||||
PyThreadState *tstate, InterpreterFrame *frame, int instr_prev)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
|
@ -5583,14 +5582,18 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
|
|||
initialize_trace_info(&tstate->trace_info, frame);
|
||||
int lastline = _PyCode_CheckLineNumber(instr_prev*2, &tstate->trace_info.bounds);
|
||||
int line = _PyCode_CheckLineNumber(frame->f_lasti*2, &tstate->trace_info.bounds);
|
||||
if (line != -1 && frame->f_trace_lines) {
|
||||
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
|
||||
if (f == NULL) {
|
||||
return -1;
|
||||
}
|
||||
if (line != -1 && f->f_trace_lines) {
|
||||
/* Trace backward edges or if line number has changed */
|
||||
if (frame->f_lasti < instr_prev || line != lastline) {
|
||||
result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None);
|
||||
}
|
||||
}
|
||||
/* Always emit an opcode event if we're tracing all opcodes. */
|
||||
if (frame->f_trace_opcodes) {
|
||||
if (f->f_trace_opcodes) {
|
||||
result = call_trace(func, obj, tstate, frame, PyTrace_OPCODE, Py_None);
|
||||
}
|
||||
return result;
|
||||
|
@ -5737,19 +5740,33 @@ _PyEval_GetAsyncGenFinalizer(void)
|
|||
return tstate->async_gen_finalizer;
|
||||
}
|
||||
|
||||
PyFrameObject *
|
||||
PyEval_GetFrame(void)
|
||||
InterpreterFrame *
|
||||
_PyEval_GetFrame(void)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
return tstate->frame;
|
||||
}
|
||||
|
||||
PyFrameObject *
|
||||
PyEval_GetFrame(void)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
if (tstate->frame == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyFrameObject *f = _PyFrame_GetFrameObject(tstate->frame);
|
||||
if (f == NULL) {
|
||||
PyErr_Clear();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyEval_GetBuiltins(PyThreadState *tstate)
|
||||
{
|
||||
PyFrameObject *frame = tstate->frame;
|
||||
InterpreterFrame *frame = tstate->frame;
|
||||
if (frame != NULL) {
|
||||
return _PyFrame_GetBuiltins(frame);
|
||||
return frame->f_builtins;
|
||||
}
|
||||
return tstate->interp->builtins;
|
||||
}
|
||||
|
@ -5780,18 +5797,17 @@ PyObject *
|
|||
PyEval_GetLocals(void)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
PyFrameObject *current_frame = tstate->frame;
|
||||
InterpreterFrame *current_frame = tstate->frame;
|
||||
if (current_frame == NULL) {
|
||||
_PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (PyFrame_FastToLocalsWithError(current_frame) < 0) {
|
||||
if (_PyFrame_FastToLocalsWithError(current_frame) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *locals = current_frame->f_valuestack[
|
||||
FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE];
|
||||
PyObject *locals = current_frame->f_locals;
|
||||
assert(locals != NULL);
|
||||
return locals;
|
||||
}
|
||||
|
@ -5800,22 +5816,22 @@ PyObject *
|
|||
PyEval_GetGlobals(void)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
PyFrameObject *current_frame = tstate->frame;
|
||||
InterpreterFrame *current_frame = tstate->frame;
|
||||
if (current_frame == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return _PyFrame_GetGlobals(current_frame);
|
||||
return current_frame->f_globals;
|
||||
}
|
||||
|
||||
int
|
||||
PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
PyFrameObject *current_frame = tstate->frame;
|
||||
InterpreterFrame *current_frame = tstate->frame;
|
||||
int result = cf->cf_flags != 0;
|
||||
|
||||
if (current_frame != NULL) {
|
||||
const int codeflags = _PyFrame_GetCode(current_frame)->co_flags;
|
||||
const int codeflags = current_frame->f_code->co_flags;
|
||||
const int compilerflags = codeflags & PyCF_MASK;
|
||||
if (compilerflags) {
|
||||
result = 1;
|
||||
|
@ -6049,22 +6065,21 @@ _PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi)
|
|||
}
|
||||
|
||||
static PyObject *
|
||||
import_name(PyThreadState *tstate, PyFrameObject *f,
|
||||
import_name(PyThreadState *tstate, InterpreterFrame *frame,
|
||||
PyObject *name, PyObject *fromlist, PyObject *level)
|
||||
{
|
||||
_Py_IDENTIFIER(__import__);
|
||||
PyObject *import_func, *res;
|
||||
PyObject* stack[5];
|
||||
|
||||
import_func = _PyDict_GetItemIdWithError(_PyFrame_GetBuiltins(f), &PyId___import__);
|
||||
import_func = _PyDict_GetItemIdWithError(frame->f_builtins, &PyId___import__);
|
||||
if (import_func == NULL) {
|
||||
if (!_PyErr_Occurred(tstate)) {
|
||||
_PyErr_SetString(tstate, PyExc_ImportError, "__import__ not found");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
PyObject *locals = f->f_valuestack[
|
||||
FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE];
|
||||
PyObject *locals = frame->f_locals;
|
||||
/* Fast path for not overloaded __import__. */
|
||||
if (import_func == tstate->interp->import_func) {
|
||||
int ilevel = _PyLong_AsInt(level);
|
||||
|
@ -6073,7 +6088,7 @@ import_name(PyThreadState *tstate, PyFrameObject *f,
|
|||
}
|
||||
res = PyImport_ImportModuleLevelObject(
|
||||
name,
|
||||
_PyFrame_GetGlobals(f),
|
||||
frame->f_globals,
|
||||
locals == NULL ? Py_None :locals,
|
||||
fromlist,
|
||||
ilevel);
|
||||
|
@ -6083,7 +6098,7 @@ import_name(PyThreadState *tstate, PyFrameObject *f,
|
|||
Py_INCREF(import_func);
|
||||
|
||||
stack[0] = name;
|
||||
stack[1] = _PyFrame_GetGlobals(f);
|
||||
stack[1] = frame->f_globals;
|
||||
stack[2] = locals == NULL ? Py_None : locals;
|
||||
stack[3] = fromlist;
|
||||
stack[4] = level;
|
||||
|
@ -6389,7 +6404,7 @@ format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int prevprevop
|
|||
|
||||
static PyObject *
|
||||
unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w,
|
||||
PyFrameObject *f, const _Py_CODEUNIT *next_instr)
|
||||
InterpreterFrame *frame, const _Py_CODEUNIT *next_instr)
|
||||
{
|
||||
PyObject *res;
|
||||
if (Py_REFCNT(v) == 2) {
|
||||
|
@ -6404,14 +6419,14 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w,
|
|||
switch (opcode) {
|
||||
case STORE_FAST:
|
||||
{
|
||||
PyObject **localsplus = f->f_localsptr;
|
||||
PyObject **localsplus = _PyFrame_GetLocalsArray(frame);
|
||||
if (GETLOCAL(oparg) == v)
|
||||
SETLOCAL(oparg, NULL);
|
||||
break;
|
||||
}
|
||||
case STORE_DEREF:
|
||||
{
|
||||
PyObject *c = f->f_localsptr[oparg];
|
||||
PyObject *c = _PyFrame_GetLocalsArray(frame)[oparg];
|
||||
if (PyCell_GET(c) == v) {
|
||||
PyCell_SET(c, NULL);
|
||||
Py_DECREF(v);
|
||||
|
@ -6420,10 +6435,9 @@ unicode_concatenate(PyThreadState *tstate, PyObject *v, PyObject *w,
|
|||
}
|
||||
case STORE_NAME:
|
||||
{
|
||||
PyObject *names = _PyFrame_GetCode(f)->co_names;
|
||||
PyObject *names = frame->f_code->co_names;
|
||||
PyObject *name = GETITEM(names, oparg);
|
||||
PyObject *locals = f->f_valuestack[
|
||||
FRAME_SPECIALS_LOCALS_OFFSET-FRAME_SPECIALS_SIZE];
|
||||
PyObject *locals = frame->f_locals;
|
||||
if (locals && PyDict_CheckExact(locals)) {
|
||||
PyObject *w = PyDict_GetItemWithError(locals, name);
|
||||
if ((w == v && PyDict_DelItem(locals, name) != 0) ||
|
||||
|
@ -6501,38 +6515,38 @@ _PyEval_RequestCodeExtraIndex(freefunc free)
|
|||
}
|
||||
|
||||
static void
|
||||
dtrace_function_entry(PyFrameObject *f)
|
||||
dtrace_function_entry(InterpreterFrame *frame)
|
||||
{
|
||||
const char *filename;
|
||||
const char *funcname;
|
||||
int lineno;
|
||||
|
||||
PyCodeObject *code = _PyFrame_GetCode(f);
|
||||
PyCodeObject *code = frame->f_code;
|
||||
filename = PyUnicode_AsUTF8(code->co_filename);
|
||||
funcname = PyUnicode_AsUTF8(code->co_name);
|
||||
lineno = PyFrame_GetLineNumber(f);
|
||||
lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti*2);
|
||||
|
||||
PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
|
||||
}
|
||||
|
||||
static void
|
||||
dtrace_function_return(PyFrameObject *f)
|
||||
dtrace_function_return(InterpreterFrame *frame)
|
||||
{
|
||||
const char *filename;
|
||||
const char *funcname;
|
||||
int lineno;
|
||||
|
||||
PyCodeObject *code = _PyFrame_GetCode(f);
|
||||
PyCodeObject *code = frame->f_code;
|
||||
filename = PyUnicode_AsUTF8(code->co_filename);
|
||||
funcname = PyUnicode_AsUTF8(code->co_name);
|
||||
lineno = PyFrame_GetLineNumber(f);
|
||||
lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti*2);
|
||||
|
||||
PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
|
||||
}
|
||||
|
||||
/* DTrace equivalent of maybe_call_line_trace. */
|
||||
static void
|
||||
maybe_dtrace_line(PyFrameObject *frame,
|
||||
maybe_dtrace_line(InterpreterFrame *frame,
|
||||
PyTraceInfo *trace_info,
|
||||
int instr_prev)
|
||||
{
|
||||
|
@ -6542,25 +6556,26 @@ maybe_dtrace_line(PyFrameObject *frame,
|
|||
instruction window, reset the window.
|
||||
*/
|
||||
initialize_trace_info(trace_info, frame);
|
||||
int lastline = _PyCode_CheckLineNumber(instr_prev*2, &trace_info->bounds);
|
||||
int line = _PyCode_CheckLineNumber(frame->f_lasti*2, &trace_info->bounds);
|
||||
/* If the last instruction falls at the start of a line or if
|
||||
it represents a jump backwards, update the frame's line
|
||||
number and call the trace function. */
|
||||
if (line != frame->f_lineno || frame->f_lasti < instr_prev) {
|
||||
if (line != -1) {
|
||||
frame->f_lineno = line;
|
||||
co_filename = PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_filename);
|
||||
if (!co_filename)
|
||||
if (line != -1) {
|
||||
/* Trace backward edges or first instruction of a new line */
|
||||
if (frame->f_lasti < instr_prev ||
|
||||
(line != lastline && frame->f_lasti*2 == trace_info->bounds.ar_start))
|
||||
{
|
||||
co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
|
||||
if (!co_filename) {
|
||||
co_filename = "?";
|
||||
co_name = PyUnicode_AsUTF8(_PyFrame_GetCode(frame)->co_name);
|
||||
if (!co_name)
|
||||
}
|
||||
co_name = PyUnicode_AsUTF8(frame->f_code->co_name);
|
||||
if (!co_name) {
|
||||
co_name = "?";
|
||||
}
|
||||
PyDTrace_LINE(co_filename, co_name, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Implement Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() as functions
|
||||
for the limited API. */
|
||||
|
||||
|
|
|
@ -1406,12 +1406,13 @@ _PyErr_WriteUnraisableMsg(const char *err_msg_str, PyObject *obj)
|
|||
}
|
||||
|
||||
if (exc_tb == NULL) {
|
||||
PyFrameObject *frame = tstate->frame;
|
||||
PyFrameObject *frame = PyThreadState_GetFrame(tstate);
|
||||
if (frame != NULL) {
|
||||
exc_tb = _PyTraceBack_FromFrame(NULL, frame);
|
||||
if (exc_tb == NULL) {
|
||||
_PyErr_Clear(tstate);
|
||||
}
|
||||
Py_DECREF(frame);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
|
||||
#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);
|
||||
for (int i = 0; i < frame->nlocalsplus; i++) {
|
||||
Py_VISIT(locals[i]);
|
||||
}
|
||||
/* stack */
|
||||
for (int i = 0; i <frame->stackdepth; i++) {
|
||||
Py_VISIT(frame->stack[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)
|
||||
{
|
||||
|
||||
Py_ssize_t size = ((char*)&frame->stack[frame->stackdepth]) - (char *)_PyFrame_GetLocalsArray(frame);
|
||||
PyObject **copy = PyMem_Malloc(size);
|
||||
if (copy == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
PyObject **locals = _PyFrame_GetLocalsArray(frame);
|
||||
memcpy(copy, locals, size);
|
||||
InterpreterFrame *res = (InterpreterFrame *)(copy + frame->nlocalsplus);
|
||||
return res;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
PyObject **localsarray = ((PyObject **)frame)-frame->nlocalsplus;
|
||||
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);
|
||||
}
|
||||
for (int i = 0; i < frame->nlocalsplus; i++) {
|
||||
Py_XDECREF(localsarray[i]);
|
||||
}
|
||||
assert(frame->stackdepth >= 0);
|
||||
for (int i = 0; i < frame->stackdepth; i++) {
|
||||
Py_DECREF(frame->stack[i]);
|
||||
}
|
||||
clear_specials(frame);
|
||||
if (take) {
|
||||
PyMem_Free(_PyFrame_GetLocalsArray(frame));
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Python.h"
|
||||
#include "pycore_ceval.h"
|
||||
#include "pycore_frame.h"
|
||||
#include "pycore_initconfig.h"
|
||||
#include "pycore_object.h" // _PyType_InitCache()
|
||||
#include "pycore_pyerrors.h"
|
||||
|
@ -685,7 +686,7 @@ new_threadstate(PyInterpreterState *interp, int init)
|
|||
PyMem_RawFree(tstate);
|
||||
return NULL;
|
||||
}
|
||||
/* If top points to entry 0, then _PyThreadState_PopLocals will try to pop this chunk */
|
||||
/* If top points to entry 0, then _PyThreadState_PopFrame will try to pop this chunk */
|
||||
tstate->datastack_top = &tstate->datastack_chunk->data[1];
|
||||
tstate->datastack_limit = (PyObject **)(((char *)tstate->datastack_chunk) + DATA_STACK_CHUNK_SIZE);
|
||||
/* Mark trace_info as uninitialized */
|
||||
|
@ -872,7 +873,7 @@ PyThreadState_Clear(PyThreadState *tstate)
|
|||
"PyThreadState_Clear: warning: thread still has a frame\n");
|
||||
}
|
||||
|
||||
/* Don't clear tstate->frame: it is a borrowed reference */
|
||||
/* Don't clear tstate->pyframe: it is a borrowed reference */
|
||||
|
||||
Py_CLEAR(tstate->dict);
|
||||
Py_CLEAR(tstate->async_exc);
|
||||
|
@ -1133,7 +1134,13 @@ PyFrameObject*
|
|||
PyThreadState_GetFrame(PyThreadState *tstate)
|
||||
{
|
||||
assert(tstate != NULL);
|
||||
PyFrameObject *frame = tstate->frame;
|
||||
if (tstate->frame == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyFrameObject *frame = _PyFrame_GetFrameObject(tstate->frame);
|
||||
if (frame == NULL) {
|
||||
PyErr_Clear();
|
||||
}
|
||||
Py_XINCREF(frame);
|
||||
return frame;
|
||||
}
|
||||
|
@ -1254,7 +1261,7 @@ _PyThread_CurrentFrames(void)
|
|||
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
|
||||
PyThreadState *t;
|
||||
for (t = i->tstate_head; t != NULL; t = t->next) {
|
||||
PyFrameObject *frame = t->frame;
|
||||
InterpreterFrame *frame = t->frame;
|
||||
if (frame == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1262,7 +1269,7 @@ _PyThread_CurrentFrames(void)
|
|||
if (id == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
int stat = PyDict_SetItem(result, id, (PyObject *)frame);
|
||||
int stat = PyDict_SetItem(result, id, (PyObject *)_PyFrame_GetFrameObject(frame));
|
||||
Py_DECREF(id);
|
||||
if (stat < 0) {
|
||||
goto fail;
|
||||
|
@ -2009,42 +2016,58 @@ _Py_GetConfig(void)
|
|||
|
||||
#define MINIMUM_OVERHEAD 1000
|
||||
|
||||
PyObject **
|
||||
_PyThreadState_PushLocals(PyThreadState *tstate, int size)
|
||||
static PyObject **
|
||||
push_chunk(PyThreadState *tstate, int size)
|
||||
{
|
||||
assert(((unsigned)size) < INT_MAX/sizeof(PyObject*)/2);
|
||||
PyObject **res = tstate->datastack_top;
|
||||
PyObject **top = res + size;
|
||||
assert(tstate->datastack_top + size >= tstate->datastack_limit);
|
||||
|
||||
int allocate_size = DATA_STACK_CHUNK_SIZE;
|
||||
while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) {
|
||||
allocate_size *= 2;
|
||||
}
|
||||
_PyStackChunk *new = allocate_chunk(allocate_size, tstate->datastack_chunk);
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
tstate->datastack_chunk->top = tstate->datastack_top - &tstate->datastack_chunk->data[0];
|
||||
tstate->datastack_chunk = new;
|
||||
tstate->datastack_limit = (PyObject **)(((char *)new) + allocate_size);
|
||||
PyObject **res = &new->data[0];
|
||||
tstate->datastack_top = res + size;
|
||||
return res;
|
||||
}
|
||||
|
||||
InterpreterFrame *
|
||||
_PyThreadState_PushFrame(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals)
|
||||
{
|
||||
PyCodeObject *code = (PyCodeObject *)con->fc_code;
|
||||
int nlocalsplus = code->co_nlocalsplus;
|
||||
size_t size = nlocalsplus + code->co_stacksize +
|
||||
FRAME_SPECIALS_SIZE;
|
||||
assert(size < INT_MAX/sizeof(PyObject *));
|
||||
PyObject **localsarray = tstate->datastack_top;
|
||||
PyObject **top = localsarray + size;
|
||||
if (top >= tstate->datastack_limit) {
|
||||
int allocate_size = DATA_STACK_CHUNK_SIZE;
|
||||
while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) {
|
||||
allocate_size *= 2;
|
||||
localsarray = push_chunk(tstate, (int)size);
|
||||
if (localsarray == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
_PyStackChunk *new = allocate_chunk(allocate_size, tstate->datastack_chunk);
|
||||
if (new == NULL) {
|
||||
goto error;
|
||||
}
|
||||
tstate->datastack_chunk->top = tstate->datastack_top - &tstate->datastack_chunk->data[0];
|
||||
tstate->datastack_chunk = new;
|
||||
tstate->datastack_limit = (PyObject **)(((char *)new) + allocate_size);
|
||||
res = &new->data[0];
|
||||
tstate->datastack_top = res + size;
|
||||
}
|
||||
else {
|
||||
tstate->datastack_top = top;
|
||||
}
|
||||
for (int i=0; i < size; i++) {
|
||||
res[i] = NULL;
|
||||
InterpreterFrame * frame = (InterpreterFrame *)(localsarray + nlocalsplus);
|
||||
_PyFrame_InitializeSpecials(frame, con, locals, nlocalsplus);
|
||||
for (int i=0; i < nlocalsplus; i++) {
|
||||
localsarray[i] = NULL;
|
||||
}
|
||||
return res;
|
||||
error:
|
||||
_PyErr_SetString(tstate, PyExc_MemoryError, "Out of memory");
|
||||
return NULL;
|
||||
return frame;
|
||||
}
|
||||
|
||||
void
|
||||
_PyThreadState_PopLocals(PyThreadState *tstate, PyObject **locals)
|
||||
_PyThreadState_PopFrame(PyThreadState *tstate, InterpreterFrame * frame)
|
||||
{
|
||||
PyObject **locals = _PyFrame_GetLocalsArray(frame);
|
||||
if (locals == &tstate->datastack_chunk->data[0]) {
|
||||
_PyStackChunk *chunk = tstate->datastack_chunk;
|
||||
_PyStackChunk *previous = chunk->previous;
|
||||
|
|
|
@ -232,7 +232,7 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc)
|
|||
return suggestions;
|
||||
}
|
||||
|
||||
dir = PySequence_List(_PyFrame_GetGlobals(frame));
|
||||
dir = PySequence_List(frame->f_frame->f_globals);
|
||||
if (dir == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ offer_suggestions_for_name_error(PyNameErrorObject *exc)
|
|||
return suggestions;
|
||||
}
|
||||
|
||||
dir = PySequence_List(_PyFrame_GetBuiltins(frame));
|
||||
dir = PySequence_List(frame->f_frame->f_builtins);
|
||||
if (dir == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ Data members:
|
|||
|
||||
#include "code.h"
|
||||
#include "frameobject.h" // PyFrame_GetBack()
|
||||
#include "pycore_frame.h"
|
||||
#include "pydtrace.h"
|
||||
#include "osdefs.h" // DELIM
|
||||
#include "stdlib_module_names.h" // _Py_stdlib_module_names
|
||||
|
@ -1814,25 +1815,22 @@ sys__getframe_impl(PyObject *module, int depth)
|
|||
/*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
PyFrameObject *f = PyThreadState_GetFrame(tstate);
|
||||
InterpreterFrame *frame = tstate->frame;
|
||||
|
||||
if (_PySys_Audit(tstate, "sys._getframe", "O", f) < 0) {
|
||||
Py_DECREF(f);
|
||||
if (_PySys_Audit(tstate, "sys._getframe", NULL) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (depth > 0 && f != NULL) {
|
||||
PyFrameObject *back = PyFrame_GetBack(f);
|
||||
Py_DECREF(f);
|
||||
f = back;
|
||||
while (depth > 0 && frame != NULL) {
|
||||
frame = frame->previous;
|
||||
--depth;
|
||||
}
|
||||
if (f == NULL) {
|
||||
if (frame == NULL) {
|
||||
_PyErr_SetString(tstate, PyExc_ValueError,
|
||||
"call stack is not deep enough");
|
||||
return NULL;
|
||||
}
|
||||
return (PyObject*)f;
|
||||
return _Py_XNewRef((PyObject *)_PyFrame_GetFrameObject(frame));
|
||||
}
|
||||
|
||||
/*[clinic input]
|
||||
|
|
|
@ -240,7 +240,7 @@ _PyTraceBack_FromFrame(PyObject *tb_next, PyFrameObject *frame)
|
|||
assert(tb_next == NULL || PyTraceBack_Check(tb_next));
|
||||
assert(frame != NULL);
|
||||
|
||||
return tb_create_raw((PyTracebackObject *)tb_next, frame, frame->f_lasti*2,
|
||||
return tb_create_raw((PyTracebackObject *)tb_next, frame, frame->f_frame->f_lasti*2,
|
||||
PyFrame_GetLineNumber(frame));
|
||||
}
|
||||
|
||||
|
@ -710,7 +710,7 @@ tb_displayline(PyTracebackObject* tb, PyObject *f, PyObject *filename, int linen
|
|||
}
|
||||
|
||||
int code_offset = tb->tb_lasti;
|
||||
PyCodeObject* code = _PyFrame_GetCode(frame);
|
||||
PyCodeObject* code = frame->f_frame->f_code;
|
||||
|
||||
int start_line;
|
||||
int end_line;
|
||||
|
@ -1024,9 +1024,9 @@ _Py_DumpASCII(int fd, PyObject *text)
|
|||
This function is signal safe. */
|
||||
|
||||
static void
|
||||
dump_frame(int fd, PyFrameObject *frame)
|
||||
dump_frame(int fd, InterpreterFrame *frame)
|
||||
{
|
||||
PyCodeObject *code = PyFrame_GetCode(frame);
|
||||
PyCodeObject *code = frame->f_code;
|
||||
PUTS(fd, " File ");
|
||||
if (code->co_filename != NULL
|
||||
&& PyUnicode_Check(code->co_filename))
|
||||
|
@ -1038,7 +1038,7 @@ dump_frame(int fd, PyFrameObject *frame)
|
|||
PUTS(fd, "???");
|
||||
}
|
||||
|
||||
int lineno = PyFrame_GetLineNumber(frame);
|
||||
int lineno = PyCode_Addr2Line(code, frame->f_lasti*2);
|
||||
PUTS(fd, ", line ");
|
||||
if (lineno >= 0) {
|
||||
_Py_DumpDecimal(fd, (size_t)lineno);
|
||||
|
@ -1057,20 +1057,19 @@ dump_frame(int fd, PyFrameObject *frame)
|
|||
}
|
||||
|
||||
PUTS(fd, "\n");
|
||||
Py_DECREF(code);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
||||
{
|
||||
PyFrameObject *frame;
|
||||
InterpreterFrame *frame;
|
||||
unsigned int depth;
|
||||
|
||||
if (write_header) {
|
||||
PUTS(fd, "Stack (most recent call first):\n");
|
||||
}
|
||||
|
||||
frame = PyThreadState_GetFrame(tstate);
|
||||
frame = tstate->frame;
|
||||
if (frame == NULL) {
|
||||
PUTS(fd, "<no Python frame>\n");
|
||||
return;
|
||||
|
@ -1079,22 +1078,14 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
|||
depth = 0;
|
||||
while (1) {
|
||||
if (MAX_FRAME_DEPTH <= depth) {
|
||||
Py_DECREF(frame);
|
||||
PUTS(fd, " ...\n");
|
||||
break;
|
||||
}
|
||||
if (!PyFrame_Check(frame)) {
|
||||
Py_DECREF(frame);
|
||||
break;
|
||||
}
|
||||
dump_frame(fd, frame);
|
||||
PyFrameObject *back = PyFrame_GetBack(frame);
|
||||
Py_DECREF(frame);
|
||||
|
||||
if (back == NULL) {
|
||||
frame = frame->previous;
|
||||
if (frame == NULL) {
|
||||
break;
|
||||
}
|
||||
frame = back;
|
||||
depth++;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -854,28 +854,102 @@ class PyNoneStructPtr(PyObjectPtr):
|
|||
def proxyval(self, visited):
|
||||
return None
|
||||
|
||||
FRAME_SPECIALS_GLOBAL_OFFSET = 0
|
||||
FRAME_SPECIALS_BUILTINS_OFFSET = 1
|
||||
FRAME_SPECIALS_CODE_OFFSET = 3
|
||||
FRAME_SPECIALS_SIZE = 4
|
||||
|
||||
class PyFrameObjectPtr(PyObjectPtr):
|
||||
_typename = 'PyFrameObject'
|
||||
|
||||
def __init__(self, gdbval, cast_to=None):
|
||||
PyObjectPtr.__init__(self, gdbval, cast_to)
|
||||
|
||||
if not self.is_optimized_out():
|
||||
self._frame = PyFramePtr(self.field('f_frame'))
|
||||
|
||||
def iter_locals(self):
|
||||
'''
|
||||
Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
|
||||
the local variables of this frame
|
||||
'''
|
||||
if self.is_optimized_out():
|
||||
return
|
||||
return self._frame.iter_locals()
|
||||
|
||||
def iter_globals(self):
|
||||
'''
|
||||
Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
|
||||
the global variables of this frame
|
||||
'''
|
||||
if self.is_optimized_out():
|
||||
return ()
|
||||
return self._frame.iter_globals()
|
||||
|
||||
def iter_builtins(self):
|
||||
'''
|
||||
Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
|
||||
the builtin variables
|
||||
'''
|
||||
if self.is_optimized_out():
|
||||
return ()
|
||||
return self._frame.iter_builtins()
|
||||
|
||||
def get_var_by_name(self, name):
|
||||
|
||||
if self.is_optimized_out():
|
||||
return None, None
|
||||
return self._frame.get_var_by_name(name)
|
||||
|
||||
def filename(self):
|
||||
'''Get the path of the current Python source file, as a string'''
|
||||
if self.is_optimized_out():
|
||||
return FRAME_INFO_OPTIMIZED_OUT
|
||||
return self._frame.filename()
|
||||
|
||||
def current_line_num(self):
|
||||
'''Get current line number as an integer (1-based)
|
||||
|
||||
Translated from PyFrame_GetLineNumber and PyCode_Addr2Line
|
||||
|
||||
See Objects/lnotab_notes.txt
|
||||
'''
|
||||
if self.is_optimized_out():
|
||||
return None
|
||||
return self._frame.current_line_num()
|
||||
|
||||
def current_line(self):
|
||||
'''Get the text of the current source line as a string, with a trailing
|
||||
newline character'''
|
||||
if self.is_optimized_out():
|
||||
return FRAME_INFO_OPTIMIZED_OUT
|
||||
return self._frame.current_line()
|
||||
|
||||
def write_repr(self, out, visited):
|
||||
if self.is_optimized_out():
|
||||
out.write(FRAME_INFO_OPTIMIZED_OUT)
|
||||
return
|
||||
return self._frame.write_repr(out, visited)
|
||||
|
||||
def print_traceback(self):
|
||||
if self.is_optimized_out():
|
||||
sys.stdout.write(' %s\n' % FRAME_INFO_OPTIMIZED_OUT)
|
||||
return
|
||||
return self._frame.print_traceback()
|
||||
|
||||
class PyFramePtr:
|
||||
|
||||
def __init__(self, gdbval):
|
||||
self._gdbval = gdbval
|
||||
|
||||
if not self.is_optimized_out():
|
||||
self.co = self._f_code()
|
||||
self.co_name = self.co.pyop_field('co_name')
|
||||
self.co_filename = self.co.pyop_field('co_filename')
|
||||
|
||||
self.f_lineno = int_from_int(self.field('f_lineno'))
|
||||
self.f_lasti = int_from_int(self.field('f_lasti'))
|
||||
self.f_lasti = self._f_lasti()
|
||||
self.co_nlocals = int_from_int(self.co.field('co_nlocals'))
|
||||
pnames = self.co.field('co_localsplusnames')
|
||||
self.co_localsplusnames = PyTupleObjectPtr.from_pyobject_ptr(pnames)
|
||||
|
||||
def is_optimized_out(self):
|
||||
return self._gdbval.is_optimized_out
|
||||
|
||||
def iter_locals(self):
|
||||
'''
|
||||
Yield a sequence of (name,value) pairs of PyObjectPtr instances, for
|
||||
|
@ -884,26 +958,34 @@ class PyFrameObjectPtr(PyObjectPtr):
|
|||
if self.is_optimized_out():
|
||||
return
|
||||
|
||||
f_localsplus = self.field('f_localsptr')
|
||||
obj_ptr_ptr = gdb.lookup_type("PyObject").pointer().pointer()
|
||||
base = self._gdbval.cast(obj_ptr_ptr)
|
||||
localsplus = base - self._f_nlocalsplus()
|
||||
for i in safe_range(self.co_nlocals):
|
||||
pyop_value = PyObjectPtr.from_pyobject_ptr(f_localsplus[i])
|
||||
pyop_value = PyObjectPtr.from_pyobject_ptr(localsplus[i])
|
||||
if pyop_value.is_null():
|
||||
continue
|
||||
pyop_name = PyObjectPtr.from_pyobject_ptr(self.co_localsplusnames[i])
|
||||
yield (pyop_name, pyop_value)
|
||||
|
||||
def _f_specials(self, index, cls=PyObjectPtr):
|
||||
f_valuestack = self.field('f_valuestack')
|
||||
return cls.from_pyobject_ptr(f_valuestack[index - FRAME_SPECIALS_SIZE])
|
||||
def _f_special(self, name, convert=PyObjectPtr.from_pyobject_ptr):
|
||||
return convert(self._gdbval[name])
|
||||
|
||||
def _f_globals(self):
|
||||
return self._f_specials(FRAME_SPECIALS_GLOBAL_OFFSET)
|
||||
return self._f_special("f_globals")
|
||||
|
||||
def _f_builtins(self):
|
||||
return self._f_specials(FRAME_SPECIALS_BUILTINS_OFFSET)
|
||||
return self._f_special("f_builtins")
|
||||
|
||||
def _f_code(self):
|
||||
return self._f_specials(FRAME_SPECIALS_CODE_OFFSET, PyCodeObjectPtr)
|
||||
return self._f_special("f_code", PyCodeObjectPtr.from_pyobject_ptr)
|
||||
|
||||
def _f_nlocalsplus(self):
|
||||
return self._f_special("nlocalsplus", int_from_int)
|
||||
|
||||
def _f_lasti(self):
|
||||
return self._f_special("f_lasti", int_from_int)
|
||||
|
||||
|
||||
def iter_globals(self):
|
||||
'''
|
||||
|
@ -960,11 +1042,6 @@ class PyFrameObjectPtr(PyObjectPtr):
|
|||
'''
|
||||
if self.is_optimized_out():
|
||||
return None
|
||||
f_trace = self.field('f_trace')
|
||||
if long(f_trace) != 0:
|
||||
# we have a non-NULL f_trace:
|
||||
return self.f_lineno
|
||||
|
||||
try:
|
||||
return self.co.addr2line(self.f_lasti*2)
|
||||
except Exception:
|
||||
|
@ -1021,6 +1098,9 @@ class PyFrameObjectPtr(PyObjectPtr):
|
|||
|
||||
out.write(')')
|
||||
|
||||
def as_address(self):
|
||||
return long(self._gdbval)
|
||||
|
||||
def print_traceback(self):
|
||||
if self.is_optimized_out():
|
||||
sys.stdout.write(' %s\n' % FRAME_INFO_OPTIMIZED_OUT)
|
||||
|
@ -1033,6 +1113,21 @@ class PyFrameObjectPtr(PyObjectPtr):
|
|||
lineno,
|
||||
self.co_name.proxyval(visited)))
|
||||
|
||||
def get_truncated_repr(self, maxlen):
|
||||
'''
|
||||
Get a repr-like string for the data, but truncate it at "maxlen" bytes
|
||||
(ending the object graph traversal as soon as you do)
|
||||
'''
|
||||
out = TruncatedStringIO(maxlen)
|
||||
try:
|
||||
self.write_repr(out, set())
|
||||
except StringTruncated:
|
||||
# Truncation occurred:
|
||||
return out.getvalue() + '...(truncated)'
|
||||
|
||||
# No truncation occurred:
|
||||
return out.getvalue()
|
||||
|
||||
class PySetObjectPtr(PyObjectPtr):
|
||||
_typename = 'PySetObject'
|
||||
|
||||
|
@ -1638,18 +1733,18 @@ class Frame(object):
|
|||
|
||||
def get_pyop(self):
|
||||
try:
|
||||
f = self._gdbframe.read_var('f')
|
||||
frame = PyFrameObjectPtr.from_pyobject_ptr(f)
|
||||
frame = self._gdbframe.read_var('frame')
|
||||
frame = PyFramePtr(frame)
|
||||
if not frame.is_optimized_out():
|
||||
return frame
|
||||
# gdb is unable to get the "f" argument of PyEval_EvalFrameEx()
|
||||
# because it was "optimized out". Try to get "f" from the frame
|
||||
# of the caller, PyEval_EvalCodeEx().
|
||||
# gdb is unable to get the "frame" argument of PyEval_EvalFrameEx()
|
||||
# because it was "optimized out". Try to get "frame" from the frame
|
||||
# of the caller, _PyEval_Vector().
|
||||
orig_frame = frame
|
||||
caller = self._gdbframe.older()
|
||||
if caller:
|
||||
f = caller.read_var('f')
|
||||
frame = PyFrameObjectPtr.from_pyobject_ptr(f)
|
||||
frame = caller.read_var('frame')
|
||||
frame = PyFramePtr(frame)
|
||||
if not frame.is_optimized_out():
|
||||
return frame
|
||||
return orig_frame
|
||||
|
|
Loading…
Reference in New Issue