8000 bpo-47177: Replace `f_lasti` with `prev_instr` by brandtbucher · Pull Request #32208 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

bpo-47177: Replace f_lasti with prev_instr #32208

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Apr 7, 2022
Merged
Next Next commit
Use a last_instr pointer instead of a lasti offset
  • Loading branch information
brandtbucher committed Mar 25, 2022
commit f7662cda394637e37944530f9c4b09d251aa97b2
12 changes: 5 additions & 7 deletions Include/internal/pycore_frame.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,6 @@ enum _frameowner {
FRAME_OWNED_BY_FRAME_OBJECT = 2
};

/*
frame->f_lasti refers to the index of the last instruction,
unless it's -1 in which case next_instr should be first_instr.
*/

typedef struct _PyInterpreterFrame {
PyFunctionObject *f_func; /* Strong reference */
PyObject *f_globals; /* Borrowed reference */
Expand All @@ -51,13 +46,16 @@ typedef struct _PyInterpreterFrame {
PyCodeObject *f_code; /* Strong reference */
PyFrameObject *frame_obj; /* Strong reference, may be NULL */
struct _PyInterpreterFrame *previous;
int f_lasti; /* Last instruction if called */
_Py_CODEUNIT *last_instr;
int stacktop; /* Offset of TOS from localsplus */
bool is_entry; // Whether this is the "root" frame for the current _PyCFrame.
char owner;
PyObject *localsplus[1];
} _PyInterpreterFrame;

#define _PyInterpreterFrame_LASTI(IF) \
((int)((IF)->last_instr - _PyCode_CODE((IF)->f_code)))

static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) {
return f->localsplus + f->f_code->co_nlocalsplus;
}
Expand Down Expand Up @@ -96,7 +94,7 @@ _PyFrame_InitializeSpecials(
frame->f_locals = Py_XNewRef(locals);
frame->stacktop = nlocalsplus;
frame->frame_obj = NULL;
frame->f_lasti = -1;
frame->last_instr = _PyCode_CODE(frame->f_code) - 1;
frame->is_entry = false;
frame->owner = FRAME_OWNED_BY_THREAD;
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/_tracemalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ static void
tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame)
{
frame->filename = &_Py_STR(anon_unknown);
int lineno = PyCode_Addr2Line(pyframe->f_code, pyframe->f_lasti*sizeof(_Py_CODEUNIT));
int lineno = PyCode_Addr2Line(pyframe->f_code, _PyInterpreterFrame_LASTI(pyframe)*sizeof(_Py_CODEUNIT));
if (lineno < 0) {
lineno = 0;
}
Expand Down
22 changes: 10 additions & 12 deletions Objects/frameobject.c
6D4E
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ PyFrame_GetLineNumber(PyFrameObject *f)
return f->f_lineno;
}
else {
return PyCode_Addr2Line(f->f_frame->f_code, f->f_frame->f_lasti*sizeof(_Py_CODEUNIT));
return PyCode_Addr2Line(f->f_frame->f_code, _PyInterpreterFrame_LASTI(f->f_frame)*sizeof(_Py_CODEUNIT));
}
}

Expand All @@ -58,10 +58,10 @@ frame_getlineno(PyFrameObject *f, void *closure)
static PyObject *
frame_getlasti(PyFrameObject *f, void *closure)
{
if (f->f_frame->f_lasti < 0) {
if (_PyInterpreterFrame_LASTI(f->f_frame) < 0) {
return PyLong_FromLong(-1);
}
return PyLong_FromLong(f->f_frame->f_lasti*sizeof(_Py_CODEUNIT));
return PyLong_FromLong(_PyInterpreterFrame_LASTI(f->f_frame)*sizeof(_Py_CODEUNIT));
}

static PyObject *
Expand Down Expand Up @@ -426,12 +426,10 @@ _PyFrame_GetState(PyFrameObject *frame)
}
case FRAME_OWNED_BY_THREAD:
{
if (frame->f_frame->f_lasti < 0) {
if (_PyInterpreterFrame_LASTI(frame->f_frame) < 0) {
return FRAME_CREATED;
}
uint8_t *code = (uint8_t *)frame->f_frame->f_code->co_code_adaptive;
int opcode = code[frame->f_frame->f_lasti*sizeof(_Py_CODEUNIT)];
switch(_PyOpcode_Deopt[opcode]) {
switch(_PyOpcode_Deopt[_Py_OPCODE(*frame->f_frame->last_instr)]) {
case COPY_FREE_VARS:
case MAKE_CELL:
case RETURN_GENERATOR:
Expand Down Expand Up @@ -562,7 +560,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_frame->f_lasti];
int64_t start_stack = stacks[_PyInterpreterFrame_LASTI(f->f_frame)];
int err = -1;
const char *msg = "cannot find bytecode for specified line";
for (int i = 0; i < len; i++) {
Expand Down Expand Up @@ -605,7 +603,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
}
/* Finally set the new lasti and return OK. */
f->f_lineno = 0;
f->f_frame->f_lasti = best_addr;
f->f_frame->last_instr = _PyCode_CODE(f->f_frame->f_code) + best_addr;
return 0;
}

Expand Down Expand Up @@ -886,7 +884,7 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg)
// This only works when opcode is a non-quickened form:
assert(_PyOpcode_Deopt[opcode] == opcode);
int check_oparg = 0;
for (int i = 0; i < frame->f_lasti; i++) {
for (int i = 0; i < _PyInterpreterFrame_LASTI(frame); i++) {
_Py_CODEUNIT instruction = _PyCode_CODE(frame->f_code)[i];
int check_opcode = _PyOpcode_Deopt[_Py_OPCODE(instruction)];
check_oparg |= _Py_OPARG(instruction);
Expand Down Expand Up @@ -920,7 +918,7 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) {
fast = _PyFrame_GetLocalsArray(frame);
// COPY_FREE_VARS has no quickened forms, so no need to use _PyOpcode_Deopt
// here:
if (frame->f_lasti < 0 && _Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS)
if (_PyInterpreterFrame_LASTI(frame) < 0 && _Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS)
{
/* Free vars have not been initialized -- Do that */
PyCodeObject *co = frame->f_code;
Expand All @@ -932,7 +930,7 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) {
frame->localsplus[offset + i] = o;
}
// COPY_FREE_VARS doesn't have inline CACHEs, either:
frame->f_lasti = 0;
frame->last_instr = _PyCode_CODE(frame->f_code);
}
for (int i = 0; i < co->co_nlocalsplus; i++) {
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
Expand Down
17 changes: 8 additions & 9 deletions Objects/genobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,14 +352,14 @@ _PyGen_yf(PyGenObject *gen)
if (gen->gi_frame_state < FRAME_CLEARED) {
_PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe;

if (frame->f_lasti < 1) {
if (_PyInterpreterFrame_LASTI(frame) < 1) {
/* Return immediately if the frame didn't start yet. SEND
always come after LOAD_CONST: a code object should not start
with SEND */
assert(_Py_OPCODE(_PyCode_CODE(gen->gi_code)[0]) != SEND);
return NULL;
}
_Py_CODEUNIT next = _PyCode_CODE(gen->gi_code)[frame->f_lasti + 1];
_Py_CODEUNIT next = _PyCode_CODE(gen->gi_code)[_PyInterpreterFrame_LASTI(frame) + 1];
if (_PyOpcode_Deopt[_Py_OPCODE(next)] != RESUME || _Py_OPARG(next) < 2)
{
/* Not in a yield from */
Expand Down Expand Up @@ -487,13 +487,12 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
// XXX: Performing this jump ourselves is awkward and problematic.
// See https://github.com/python/cpython/pull/31968.
/* Termination repetition of SEND loop */
assert(frame->f_lasti >= 0);
_Py_CODEUNIT *code = _PyCode_CODE(gen->gi_code);
assert(_PyInterpreterFrame_LASTI(frame) >= 0);
/* Backup to SEND */
frame->f_lasti--;
assert(_Py_OPCODE(code[frame->f_lasti]) == SEND);
int jump = _Py_OPARG(code[frame->f_lasti]);
frame->f_lasti += jump;
frame->last_instr--;
assert(_Py_OPCODE(*frame->last_instr) == SEND);
int jump = _Py_OPARG(*frame->last_instr);
frame->last_instr += jump;
if (_PyGen_FetchStopIterationValue(&val) == 0) {
ret = gen_send(gen, val);
Py_DECREF(val);
Expand Down Expand Up @@ -1340,7 +1339,7 @@ compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame)
PyCodeObject *code = frame->f_code;
PyObject *frameinfo = Py_BuildValue("OiO",
code->co_filename,
PyCode_Addr2Line(frame->f_code, frame->f_lasti*sizeof(_Py_CODEUNIT)),
PyCode_Addr2Line(frame->f_code, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT)),
code->co_name);
if (!frameinfo) {
Py_DECREF(cr_origin);
Expand Down
2 changes: 1 addition & 1 deletion Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -8948,7 +8948,7 @@ super_init_without_args(_PyInterpreterFrame *cframe, PyCodeObject *co,
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 (cframe->f_lasti >= 0) {
if (_PyInterpreterFrame_LASTI(cframe) >= 0) {
// MAKE_CELL and COPY_FREE_VARS have no quickened forms, so no need
// to use _PyOpcode_Deopt here:
assert(_Py_OPCODE(_PyCode_CODE(co)[0]) == MAKE_CELL ||
Expand Down
55 changes: 26 additions & 29 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,10 @@ static int prtrace(PyThreadState *, PyObject *, const char *);
static void lltrace_instruction(_PyInterpreterFrame *frame, int opcode, int oparg)
{
if (HAS_ARG(opcode)) {
printf("%d: %d, %d\n",
frame->f_lasti, opcode, oparg);
printf("%d: %d, %d\n", _PyInterpreterFrame_LASTI(frame), opcode, oparg);
}
else {
printf("%d: %d\n",
frame->f_lasti, opcode);
printf("%d: %d\n", _PyInterpreterFrame_LASTI(frame), opcode);
}
}
#endif
Expand Down Expand Up @@ -1249,14 +1247,13 @@ eval_frame_handle_pending(PyThreadState *tstate)
#ifdef Py_STATS
#define INSTRUCTION_START(op) \
do { \
frame->f_lasti = INSTR_OFFSET(); \
next_instr++; \
frame->last_instr = next_instr++; \
OPCODE_EXE_INC(op); \
_py_stats.opcode_stats[lastopcode].pair_count[op]++; \
lastopcode = op; \
} while (0)
#else
#define INSTRUCTION_START(op) frame->f_lasti = INSTR_OFFSET(); next_instr++
#define INSTRUCTION_START(op) (frame->last_instr = next_instr++)
#endif

#if USE_COMPUTED_GOTOS
Expand Down Expand Up @@ -1645,9 +1642,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
consts = co->co_consts; \
first_instr = _PyCode_CODE(co); \
} \
assert(frame->f_lasti >= -1); \
assert(_PyInterpreterFrame_LASTI(frame) >= -1); \
/* Jump back to the last instruction executed... */ \
next_instr = first_instr + frame->f_lasti + 1; \
next_instr = frame->last_instr + 1; \
stack_pointer = _PyFrame_GetStackPointer(frame); \
/* Set stackdepth to -1. \
Update when returning or calling trace function. \
Expand Down Expand Up @@ -2198,7 +2195,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
new_frame->localsplus[i] = NULL;
}
_PyFrame_SetStackPointer(frame, stack_pointer);
frame->f_lasti += INLINE_CACHE_ENTRIES_BINARY_SUBSCR;
frame->last_instr += INLINE_CACHE_ENTRIES_BINARY_SUBSCR;
new_frame->previous = frame;
frame = cframe.current_frame = new_frame;
CALL_STAT_INC(inlined_py_calls);
Expand Down Expand Up @@ -2602,7 +2599,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
if (oparg) {
PyObject *lasti = PEEK(oparg + 1);
if (PyLong_Check(lasti)) {
frame->f_lasti = PyLong_AsLong(lasti);
frame->last_instr = first_instr + PyLong_AsLong(lasti);
assert(!_PyErr_Occurred(tstate));
}
else {
Expand Down Expand Up @@ -4614,7 +4611,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
goto error;
}
_PyFrame_SetStackPointer(frame, stack_pointer);
frame->f_lasti += INLINE_CACHE_ENTRIES_CALL;
frame->last_instr += INLINE_CACHE_ENTRIES_CALL;
new_frame->previous = frame;
cframe.current_frame = frame = new_frame;
CALL_STAT_INC(inlined_py_calls);
Expand Down Expand Up @@ -4719,7 +4716,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
}
STACK_SHRINK(2-is_meth);
_PyFrame_SetStackPointer(frame, stack_pointer);
frame->f_lasti += INLINE_CACHE_ENTRIES_CALL;
frame->last_instr += INLINE_CACHE_ENTRIES_CALL;
new_frame->previous = frame;
frame = cframe.current_frame = new_frame;
goto start_frame;
Expand Down Expand Up @@ -4759,7 +4756,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
}
STACK_SHRINK(2-is_meth);
_PyFrame_SetStackPointer(frame, stack_pointer);
frame->f_lasti += INLINE_CACHE_ENTRIES_CALL;
frame->last_instr += INLINE_CACHE_ENTRIES_CALL;
new_frame->previous = frame;
frame = cframe.current_frame = new_frame;
goto start_frame;
Expand Down Expand Up @@ -5416,8 +5413,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
#endif
{
if (tstate->tracing == 0) {
int instr_prev = frame->f_lasti;
frame->f_lasti = INSTR_OFFSET();
int instr_prev = _PyInterpreterFrame_LASTI(frame);
frame->last_instr = next_instr;
TRACING_NEXTOPARG();
switch(opcode) {
case COPY_FREE_VARS:
Expand Down Expand Up @@ -5455,7 +5452,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
goto error;
}
/* Reload possibly changed frame fields */
JUMPTO(frame->f_lasti);
JUMPTO(_PyInterpreterFrame_LASTI(frame));

stack_pointer = _PyFrame_GetStackPointer(frame);
frame->stacktop = -1;
Expand All @@ -5474,7 +5471,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
#endif
fprintf(stderr,
"XXX lineno: %d, opcode: %d\n",
PyCode_Addr2Line(frame->f_code, frame->f_lasti*sizeof(_Py_CODEUNIT)),
PyCode_Addr2Line(frame->f_code, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT)),
opcode);
_PyErr_SetString(tstate, PyExc_SystemError, "unknown opcode");
goto error;
Expand Down Expand Up @@ -5588,7 +5585,7 @@ MISS_WITH_INLINE_CACHE(STORE_SUBSCR)
}
PyObject *exc, *val, *tb;
if (lasti) {
PyObject *lasti = PyLong_FromLong(frame->f_lasti);
PyObject *lasti = PyLong_FromLong(_PyInterpreterFrame_LASTI(frame));
if (lasti == NULL) {
goto exception_unwind;
}
Expand Down Expand Up @@ -6680,9 +6677,9 @@ call_trace(Py_tracefunc func, PyObject *obj,
int old_what = tstate->tracing_what;
tstate->tracing_what = what;
PyThreadState_EnterTracing(tstate);
assert (frame->f_lasti >= 0);
assert(_PyInterpreterFrame_LASTI(frame) >= 0);
initialize_trace_info(&tstate->trace_info, frame);
f->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds);
f->f_lineno = _PyCode_CheckLineNumber(_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds);
result = func(obj, f, what, arg);
f->f_lineno = 0;
PyThreadState_LeaveTracing(tstate);
Expand Down Expand Up @@ -6732,18 +6729,18 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
else {
lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds);
}
int line = _PyCode_CheckLineNumber(frame->f_lasti*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds);
int line = _PyCode_CheckLineNumber(_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds);
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
if (f == NULL) {
return -1;
}
if (line != -1 && f->f_trace_lines) {
/* Trace backward edges (except in 'yield from') or if line number has changed */
int trace = line != lastline ||
(frame->f_lasti < instr_prev &&
(_PyInterpreterFrame_LASTI(frame) < instr_prev &&
// SEND has no quickened forms, so no need to use _PyOpcode_Deopt
// here:
_Py_OPCODE(_PyCode_CODE(frame->f_code)[frame->f_lasti]) != SEND);
_Py_OPCODE(*frame->last_instr) != SEND);
if (trace) {
result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None);
}
Expand Down Expand Up @@ -7675,7 +7672,7 @@ dtrace_function_entry(_PyInterpreterFrame *frame)
PyCodeObject *code = frame->f_code;
filename = PyUnicode_AsUTF8(code->co_filename);
funcname = PyUnicode_AsUTF8(code->co_name);
lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti*sizeof(_Py_CODEUNIT));
lineno = PyCode_Addr2Line(frame->f_code, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT));

PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
}
Expand All @@ -7690,7 +7687,7 @@ dtrace_function_return(_PyInterpreterFrame *frame)
PyCodeObject *code = frame->f_code;
filename = PyUnicode_AsUTF8(code->co_filename);
funcname = PyUnicode_AsUTF8(code->co_name);
lineno = PyCode_Addr2Line(frame->f_code, frame->f_lasti*sizeof(_Py_CODEUNIT));
lineno = PyCode_Addr2Line(frame->f_code, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT));

PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
}
Expand All @@ -7708,11 +7705,11 @@ maybe_dtrace_line(_PyInterpreterFrame *frame,
*/
initialize_trace_info(trace_info, frame);
int lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &trace_info->bounds);
int line = _PyCode_CheckLineNumber(frame->f_lasti*sizeof(_Py_CODEUNIT), &trace_info->bounds);
int line = _PyCode_CheckLineNumber(_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT), &trace_info->bounds);
if (line != -1) {
/* Trace backward edges or first instruction of a new line */
if (frame->f_lasti < instr_prev ||
(line != lastline && frame->f_lasti*sizeof(_Py_CODEUNIT) == (unsigned int)trace_info->bounds.ar_start))
if (_PyInterpreterFrame_LASTI(frame) < instr_prev ||
(line != lastline && _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT) == (unsigned int)trace_info->bounds.ar_start))
{
co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
if (!co_filename) {
Expand Down
4 changes: 2 additions & 2 deletions Python/traceback.c
Original file line number Diff line number Diff line change
Expand Up @@ -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_frame->f_lasti*sizeof(_Py_CODEUNIT),
return tb_create_raw((PyTracebackObject *)tb_next, frame, _PyInterpreterFrame_LASTI(frame->f_frame)*sizeof(_Py_CODEUNIT),
PyFrame_GetLineNumber(frame));
}

Expand Down Expand Up @@ -1181,7 +1181,7 @@ dump_frame(int fd, _PyInterpreterFrame *frame)
PUTS(fd, "???");
}

int lineno = PyCode_Addr2Line(code, frame->f_lasti*sizeof(_Py_CODEUNIT));
int lineno = PyCode_Addr2Line(code, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT));
PUTS(fd, ", line ");
if (lineno >= 0) {
_Py_DumpDecimal(fd, (size_t)lineno);
Expand Down
Loading
0