summaryrefslogtreecommitdiff
path: root/Python
diff options
context:
space:
mode:
Diffstat (limited to 'Python')
-rw-r--r--Python/_warnings.c6
-rw-r--r--Python/ceval.c431
-rw-r--r--Python/errors.c3
-rw-r--r--Python/frame.c135
-rw-r--r--Python/pystate.c81
-rw-r--r--Python/suggestions.c4
-rw-r--r--Python/sysmodule.c16
-rw-r--r--Python/traceback.c29
8 files changed, 433 insertions, 272 deletions
diff --git a/Python/_warnings.c b/Python/_warnings.c
index 9f68da2087..cf2110d31c 100644
--- a/Python/_warnings.c
+++ b/Python/_warnings.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);
diff --git a/Python/ceval.c b/Python/ceval.c
index 90112aa3f9..02eef9bc1c 100644
--- a/Python/ceval.c
+++ b/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;
- }
- else {
- int size = code->co_nlocalsplus + code->co_stacksize +
- FRAME_SPECIALS_SIZE;
- localsarray = _PyThreadState_PushLocals(tstate, size);
- if (localsarray == NULL) {
- return NULL;
- }
+ return make_coro(tstate, con, locals, args, argcount, kwnames);
}
- 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);
- }
- 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;
+ assert (tstate->interp->eval_frame != NULL);
+ PyObject *retval = _PyEval_EvalFrame(tstate, frame, 0);
+ assert(frame->stackdepth == 0);
+ if (_PyEvalFrameClearAndPop(tstate, frame)) {
+ retval = NULL;
}
- _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;
}
+InterpreterFrame *
+_PyEval_GetFrame(void)
+{
+ PyThreadState *tstate = _PyThreadState_GET();
+ return tstate->frame;
+}
+
PyFrameObject *
PyEval_GetFrame(void)
{
PyThreadState *tstate = _PyThreadState_GET();
- return tstate->frame;
+ 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. */
diff --git a/Python/errors.c b/Python/errors.c
index 118118ffe9..1f84215a13 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -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);
}
}
diff --git a/Python/frame.c b/Python/frame.c
new file mode 100644
index 0000000000..ae4284346e
--- /dev/null
+++ b/Python/frame.c
@@ -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;
+}
diff --git a/Python/pystate.c b/Python/pystate.c
index a94a615f39..6a15b54d1d 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -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(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)
{
- assert(((unsigned)size) < INT_MAX/sizeof(PyObject*)/2);
- PyObject **res = tstate->datastack_top;
- PyObject **top = res + size;
+ 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;
- }
- _PyStackChunk *new = allocate_chunk(allocate_size, tstate->datastack_chunk);
- if (new == NULL) {
- goto error;
+ localsarray = push_chunk(tstate, (int)size);
+ if (localsarray == 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);
- 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;
diff --git a/Python/suggestions.c b/Python/suggestions.c
index 77bdb6c165..81976ff4f2 100644
--- a/Python/suggestions.c
+++ b/Python/suggestions.c
@@ -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;
}
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index f809e2fda5..5dfa917e8f 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -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]
diff --git a/Python/traceback.c b/Python/traceback.c
index 6d230138a3..204121ba66 100644
--- a/Python/traceback.c
+++ b/Python/traceback.c
@@ -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));
}
@@ -521,7 +521,7 @@ _Py_DisplaySourceLine(PyObject *f, PyObject *filename, int lineno, int indent, i
* When displaying a new traceback line, for certain syntactical constructs
* (e.g a subscript, an arithmetic operation) we try to create a representation
* that separates the primary source of error from the rest.
- *
+ *
* Example specialization of BinOp nodes:
* Traceback (most recent call last):
* File "/home/isidentical/cpython/cpython/t.py", line 10, in <module>
@@ -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++;
}
}