mirror of
https://github.com/python/cpython.git
synced 2025-10-21 14:12:27 +00:00
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
27 changed files with 1037 additions and 619 deletions
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. */
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue