From f7662cda394637e37944530f9c4b09d251aa97b2 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 25 Mar 2022 11:29:28 -0700 Subject: [PATCH 01/12] Use a last_instr pointer instead of a lasti offset --- Include/internal/pycore_frame.h | 12 +++---- Modules/_tracemalloc.c | 2 +- Objects/frameobject.c | 22 ++++++------- Objects/genobject.c | 17 +++++----- Objects/typeobject.c | 2 +- Python/ceval.c | 55 ++++++++++++++++----------------- Python/traceback.c | 4 +-- Tools/gdb/libpython.py | 5 ++- 8 files changed, 57 insertions(+), 62 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 14fba8cd1f941c..b8f978c2cdf75b 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -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 */ @@ -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; } @@ -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; } diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index 738d54530c9674..79202d5a551104 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -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; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 5c6a8bcb9008da..4b4cebfaafc001 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -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)); } } @@ -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 * @@ -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: @@ -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++) { @@ -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; } @@ -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); @@ -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; @@ -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); diff --git a/Objects/genobject.c b/Objects/genobject.c index f071390d6d32bb..8222267bd74354 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -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 */ @@ -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); @@ -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); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4bed3ef49289ae..cc4bbe84f7e91f 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -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 || diff --git a/Python/ceval.c b/Python/ceval.c index e1d961fee6a832..c4821b0d269108 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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 @@ -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 @@ -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. \ @@ -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); @@ -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 { @@ -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); @@ -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; @@ -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; @@ -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: @@ -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; @@ -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; @@ -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; } @@ -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); @@ -6732,7 +6729,7 @@ 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; @@ -6740,10 +6737,10 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, 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); } @@ -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); } @@ -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); } @@ -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) { diff --git a/Python/traceback.c b/Python/traceback.c index 6a721cf9097573..8ac1bc06bb87c8 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_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)); } @@ -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); diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 00cdcca084e742..ad14aa12281aba 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -1015,7 +1015,10 @@ def _f_nlocalsplus(self): return self._f_special("nlocalsplus", int_from_int) def _f_lasti(self): - return self._f_special("f_lasti", int_from_int) + _Py_CODEUNIT = gdb.lookup_type("_Py_CODEUNIT") + last_instr = self._gdbval["last_instr"] + first_instr = self._f_code().field("co_code_adaptive").cast(_Py_CODEUNIT.pointer()) + return int(last_instr - first_instr) def is_entry(self): return self._f_special("is_entry", bool) From 840e14cb4fcf4356b923e2ad17fd8fb24f15cc75 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 25 Mar 2022 11:56:37 -0700 Subject: [PATCH 02/12] Use next_instr instead of last_instr --- Include/internal/pycore_frame.h | 6 +++--- Objects/frameobject.c | 6 +++--- Objects/genobject.c | 8 ++++---- Python/ceval.c | 20 ++++++++++---------- Tools/gdb/libpython.py | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index b8f978c2cdf75b..5885235ed672f8 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -46,7 +46,7 @@ typedef struct _PyInterpreterFrame { PyCodeObject *f_code; /* Strong reference */ PyFrameObject *frame_obj; /* Strong reference, may be NULL */ struct _PyInterpreterFrame *previous; - _Py_CODEUNIT *last_instr; + _Py_CODEUNIT *next_instr; int stacktop; /* Offset of TOS from localsplus */ bool is_entry; // Whether this is the "root" frame for the current _PyCFrame. char owner; @@ -54,7 +54,7 @@ typedef struct _PyInterpreterFrame { } _PyInterpreterFrame; #define _PyInterpreterFrame_LASTI(IF) \ - ((int)((IF)->last_instr - _PyCode_CODE((IF)->f_code))) + ((int)((IF)->next_instr - _PyCode_CODE((IF)->f_code)) - 1) static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { return f->localsplus + f->f_code->co_nlocalsplus; @@ -94,7 +94,7 @@ _PyFrame_InitializeSpecials( frame->f_locals = Py_XNewRef(locals); frame->stacktop = nlocalsplus; frame->frame_obj = NULL; - frame->last_instr = _PyCode_CODE(frame->f_code) - 1; + frame->next_instr = _PyCode_CODE(frame->f_code); frame->is_entry = false; frame->owner = FRAME_OWNED_BY_THREAD; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 4b4cebfaafc001..87c5446ff67611 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -429,7 +429,7 @@ _PyFrame_GetState(PyFrameObject *frame) if (_PyInterpreterFrame_LASTI(frame->f_frame) < 0) { return FRAME_CREATED; } - switch(_PyOpcode_Deopt[_Py_OPCODE(*frame->f_frame->last_instr)]) { + switch(_PyOpcode_Deopt[_Py_OPCODE(frame->f_frame->next_instr[-1])]) { case COPY_FREE_VARS: case MAKE_CELL: case RETURN_GENERATOR: @@ -603,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->last_instr = _PyCode_CODE(f->f_frame->f_code) + best_addr; + f->f_frame->next_instr = _PyCode_CODE(f->f_frame->f_code) + best_addr + 1; return 0; } @@ -930,7 +930,7 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) { frame->localsplus[offset + i] = o; } // COPY_FREE_VARS doesn't have inline CACHEs, either: - frame->last_instr = _PyCode_CODE(frame->f_code); + frame->next_instr = _PyCode_CODE(frame->f_code) + 1; } for (int i = 0; i < co->co_nlocalsplus; i++) { _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i); diff --git a/Objects/genobject.c b/Objects/genobject.c index 8222267bd74354..14a77839548dde 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -489,10 +489,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, /* Termination repetition of SEND loop */ assert(_PyInterpreterFrame_LASTI(frame) >= 0); /* Backup to SEND */ - frame->last_instr--; - assert(_Py_OPCODE(*frame->last_instr) == SEND); - int jump = _Py_OPARG(*frame->last_instr); - frame->last_instr += jump; + frame->next_instr--; + assert(_Py_OPCODE(frame->next_instr[-1]) == SEND); + int jump = _Py_OPARG(frame->next_instr[-1]); + frame->next_instr += jump; if (_PyGen_FetchStopIterationValue(&val) == 0) { ret = gen_send(gen, val); Py_DECREF(val); diff --git a/Python/ceval.c b/Python/ceval.c index c4821b0d269108..3d996f86cc1d93 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1247,13 +1247,13 @@ eval_frame_handle_pending(PyThreadState *tstate) #ifdef Py_STATS #define INSTRUCTION_START(op) \ do { \ - frame->last_instr = next_instr++; \ + frame->next_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->last_instr = next_instr++) +#define INSTRUCTION_START(op) (frame->next_instr = ++next_instr) #endif #if USE_COMPUTED_GOTOS @@ -1644,7 +1644,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } \ assert(_PyInterpreterFrame_LASTI(frame) >= -1); \ /* Jump back to the last instruction executed... */ \ - next_instr = frame->last_instr + 1; \ + next_instr = frame->next_instr; \ stack_pointer = _PyFrame_GetStackPointer(frame); \ /* Set stackdepth to -1. \ Update when returning or calling trace function. \ @@ -2195,7 +2195,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int new_frame->localsplus[i] = NULL; } _PyFrame_SetStackPointer(frame, stack_pointer); - frame->last_instr += INLINE_CACHE_ENTRIES_BINARY_SUBSCR; + frame->next_instr += INLINE_CACHE_ENTRIES_BINARY_SUBSCR; new_frame->previous = frame; frame = cframe.current_frame = new_frame; CALL_STAT_INC(inlined_py_calls); @@ -2599,7 +2599,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int if (oparg) { PyObject *lasti = PEEK(oparg + 1); if (PyLong_Check(lasti)) { - frame->last_instr = first_instr + PyLong_AsLong(lasti); + frame->next_instr = first_instr + PyLong_AsLong(lasti) + 1; assert(!_PyErr_Occurred(tstate)); } else { @@ -4611,7 +4611,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto error; } _PyFrame_SetStackPointer(frame, stack_pointer); - frame->last_instr += INLINE_CACHE_ENTRIES_CALL; + frame->next_instr += INLINE_CACHE_ENTRIES_CALL; new_frame->previous = frame; cframe.current_frame = frame = new_frame; CALL_STAT_INC(inlined_py_calls); @@ -4716,7 +4716,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } STACK_SHRINK(2-is_meth); _PyFrame_SetStackPointer(frame, stack_pointer); - frame->last_instr += INLINE_CACHE_ENTRIES_CALL; + frame->next_instr += INLINE_CACHE_ENTRIES_CALL; new_frame->previous = frame; frame = cframe.current_frame = new_frame; goto start_frame; @@ -4756,7 +4756,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } STACK_SHRINK(2-is_meth); _PyFrame_SetStackPointer(frame, stack_pointer); - frame->last_instr += INLINE_CACHE_ENTRIES_CALL; + frame->next_instr += INLINE_CACHE_ENTRIES_CALL; new_frame->previous = frame; frame = cframe.current_frame = new_frame; goto start_frame; @@ -5414,7 +5414,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int { if (tstate->tracing == 0) { int instr_prev = _PyInterpreterFrame_LASTI(frame); - frame->last_instr = next_instr; + frame->next_instr = next_instr + 1; TRACING_NEXTOPARG(); switch(opcode) { case COPY_FREE_VARS: @@ -6740,7 +6740,7 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, (_PyInterpreterFrame_LASTI(frame) < instr_prev && // SEND has no quickened forms, so no need to use _PyOpcode_Deopt // here: - _Py_OPCODE(*frame->last_instr) != SEND); + _Py_OPCODE(frame->next_instr[-1]) != SEND); if (trace) { result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index ad14aa12281aba..0a54ff2f36e017 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -1016,9 +1016,9 @@ def _f_nlocalsplus(self): def _f_lasti(self): _Py_CODEUNIT = gdb.lookup_type("_Py_CODEUNIT") - last_instr = self._gdbval["last_instr"] + next_instr = self._gdbval["next_instr"] first_instr = self._f_code().field("co_code_adaptive").cast(_Py_CODEUNIT.pointer()) - return int(last_instr - first_instr) + return int(next_instr - first_instr - 1) def is_entry(self): return self._f_special("is_entry", bool) From 804d95d6aff22fdccd137b2d725d57001e1c5157 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 25 Mar 2022 15:22:22 -0700 Subject: [PATCH 03/12] Clean things up a bit --- Modules/_tracemalloc.c | 3 ++- Objects/frameobject.c | 26 +++++++++++++++----------- Objects/genobject.c | 15 +++++++-------- Python/ceval.c | 35 ++++++++++++++++++++--------------- Python/traceback.c | 7 ++++--- 5 files changed, 48 insertions(+), 38 deletions(-) diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index 79202d5a551104..d9fb6c7255d2ff 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -308,7 +308,8 @@ static void tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) { frame->filename = &_Py_STR(anon_unknown); - int lineno = PyCode_Addr2Line(pyframe->f_code, _PyInterpreterFrame_LASTI(pyframe)*sizeof(_Py_CODEUNIT)); + int addr = _PyInterpreterFrame_LASTI(pyframe) * sizeof(_Py_CODEUNIT); + int lineno = PyCode_Addr2Line(pyframe->f_code, addr); if (lineno < 0) { lineno = 0; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 87c5446ff67611..588f22664fcc5a 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -39,7 +39,8 @@ PyFrame_GetLineNumber(PyFrameObject *f) return f->f_lineno; } else { - return PyCode_Addr2Line(f->f_frame->f_code, _PyInterpreterFrame_LASTI(f->f_frame)*sizeof(_Py_CODEUNIT)); + int addr = _PyInterpreterFrame_LASTI(f->f_frame) * sizeof(_Py_CODEUNIT); + return PyCode_Addr2Line(f->f_frame->f_code, addr); } } @@ -58,10 +59,11 @@ frame_getlineno(PyFrameObject *f, void *closure) static PyObject * frame_getlasti(PyFrameObject *f, void *closure) { - if (_PyInterpreterFrame_LASTI(f->f_frame) < 0) { + int lasti = _PyInterpreterFrame_LASTI(f->f_frame); + if (lasti < 0) { return PyLong_FromLong(-1); } - return PyLong_FromLong(_PyInterpreterFrame_LASTI(f->f_frame)*sizeof(_Py_CODEUNIT)); + return PyLong_FromLong(lasti * sizeof(_Py_CODEUNIT)); } static PyObject * @@ -429,7 +431,8 @@ _PyFrame_GetState(PyFrameObject *frame) if (_PyInterpreterFrame_LASTI(frame->f_frame) < 0) { return FRAME_CREATED; } - switch(_PyOpcode_Deopt[_Py_OPCODE(frame->f_frame->next_instr[-1])]) { + switch (_PyOpcode_Deopt[_Py_OPCODE(frame->f_frame->next_instr[-1])]) + { case COPY_FREE_VARS: case MAKE_CELL: case RETURN_GENERATOR: @@ -884,10 +887,11 @@ _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 < _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); + for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code); + instruction < frame->next_instr; instruction++) + { + int check_opcode = _PyOpcode_Deopt[_Py_OPCODE(*instruction)]; + check_oparg |= _Py_OPARG(*instruction); if (check_opcode == opcode && check_oparg == oparg) { return 1; } @@ -897,7 +901,7 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg) else { check_oparg = 0; } - i += _PyOpcode_Caches[check_opcode]; + instruction += _PyOpcode_Caches[check_opcode]; } return 0; } @@ -918,8 +922,8 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) { fast = _PyFrame_GetLocalsArray(frame); // COPY_FREE_VARS has no quickened forms, so no need to use _PyOpcode_Deopt // here: - if (_PyInterpreterFrame_LASTI(frame) < 0 && _Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS) - { + int lasti = _PyInterpreterFrame_LASTI(frame); + if (lasti < 0 && _Py_OPCODE(_PyCode_CODE(co)[0]) == COPY_FREE_VARS) { /* Free vars have not been initialized -- Do that */ PyCodeObject *co = frame->f_code; PyObject *closure = frame->f_func->func_closure; diff --git a/Objects/genobject.c b/Objects/genobject.c index 14a77839548dde..16d4fd825b33c9 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -359,7 +359,7 @@ _PyGen_yf(PyGenObject *gen) assert(_Py_OPCODE(_PyCode_CODE(gen->gi_code)[0]) != SEND); return NULL; } - _Py_CODEUNIT next = _PyCode_CODE(gen->gi_code)[_PyInterpreterFrame_LASTI(frame) + 1]; + _Py_CODEUNIT next = *frame->next_instr; if (_PyOpcode_Deopt[_Py_OPCODE(next)] != RESUME || _Py_OPARG(next) < 2) { /* Not in a yield from */ @@ -489,10 +489,9 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, /* Termination repetition of SEND loop */ assert(_PyInterpreterFrame_LASTI(frame) >= 0); /* Backup to SEND */ - frame->next_instr--; - assert(_Py_OPCODE(frame->next_instr[-1]) == SEND); - int jump = _Py_OPARG(frame->next_instr[-1]); - frame->next_instr += jump; + assert(_Py_OPCODE(frame->next_instr[-2]) == SEND); + int jump = _Py_OPARG(frame->next_instr[-2]); + frame->next_instr += jump - 1; if (_PyGen_FetchStopIterationValue(&val) == 0) { ret = gen_send(gen, val); Py_DECREF(val); @@ -1337,9 +1336,9 @@ compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame) frame = current_frame; for (int i = 0; i < frame_count; ++i) { PyCodeObject *code = frame->f_code; - PyObject *frameinfo = Py_BuildValue("OiO", - code->co_filename, - PyCode_Addr2Line(frame->f_code, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT)), + int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); + int line = PyCode_Addr2Line(frame->f_code, addr); + PyObject *frameinfo = Py_BuildValue("OiO", code->co_filename, line, code->co_name); if (!frameinfo) { Py_DECREF(cr_origin); diff --git a/Python/ceval.c b/Python/ceval.c index 3d996f86cc1d93..f4ff693498b010 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -5452,7 +5452,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto error; } /* Reload possibly changed frame fields */ - JUMPTO(_PyInterpreterFrame_LASTI(frame)); + next_instr = frame->next_instr - 1; stack_pointer = _PyFrame_GetStackPointer(frame); frame->stacktop = -1; @@ -5469,10 +5469,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #else default: #endif - fprintf(stderr, - "XXX lineno: %d, opcode: %d\n", - PyCode_Addr2Line(frame->f_code, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT)), - opcode); + ; + int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); + int line = PyCode_Addr2Line(frame->f_code, addr); + fprintf(stderr, "XXX lineno: %d, opcode: %d\n", line, opcode); _PyErr_SetString(tstate, PyExc_SystemError, "unknown opcode"); goto error; @@ -5585,7 +5585,8 @@ MISS_WITH_INLINE_CACHE(STORE_SUBSCR) } PyObject *exc, *val, *tb; if (lasti) { - PyObject *lasti = PyLong_FromLong(_PyInterpreterFrame_LASTI(frame)); + int frame_lasti = _PyInterpreterFrame_LASTI(frame); + PyObject *lasti = PyLong_FromLong(frame_lasti); if (lasti == NULL) { goto exception_unwind; } @@ -6679,7 +6680,8 @@ call_trace(Py_tracefunc func, PyObject *obj, PyThreadState_EnterTracing(tstate); assert(_PyInterpreterFrame_LASTI(frame) >= 0); initialize_trace_info(&tstate->trace_info, frame); - f->f_lineno = _PyCode_CheckLineNumber(_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); + int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); + f->f_lineno = _PyCode_CheckLineNumber(addr, &tstate->trace_info.bounds); result = func(obj, f, what, arg); f->f_lineno = 0; PyThreadState_LeaveTracing(tstate); @@ -6729,7 +6731,8 @@ 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(_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); + int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); + int line = _PyCode_CheckLineNumber(addr, &tstate->trace_info.bounds); PyFrameObject *f = _PyFrame_GetFrameObject(frame); if (f == NULL) { return -1; @@ -6738,9 +6741,9 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, /* Trace backward edges (except in 'yield from') or if line number has changed */ int trace = line != lastline || (_PyInterpreterFrame_LASTI(frame) < instr_prev && - // SEND has no quickened forms, so no need to use _PyOpcode_Deopt - // here: - _Py_OPCODE(frame->next_instr[-1]) != SEND); + // SEND has no quickened forms, so no need to use _PyOpcode_Deopt + // here: + _Py_OPCODE(frame->next_instr[-1]) != SEND); if (trace) { result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } @@ -7672,7 +7675,8 @@ 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, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT)); + int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); + lineno = PyCode_Addr2Line(frame->f_code, addr); PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno); } @@ -7687,7 +7691,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, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT)); + lineno = PyCode_Addr2Line(frame->f_code, _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT)); PyDTrace_FUNCTION_RETURN(filename, funcname, lineno); } @@ -7705,11 +7709,12 @@ 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(_PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT), &trace_info->bounds); + int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); + int line = _PyCode_CheckLineNumber(addr, &trace_info->bounds); if (line != -1) { /* Trace backward edges or first instruction of a new line */ if (_PyInterpreterFrame_LASTI(frame) < instr_prev || - (line != lastline && _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT) == (unsigned int)trace_info->bounds.ar_start)) + (line != lastline && addr == trace_info->bounds.ar_start)) { co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename); if (!co_filename) { diff --git a/Python/traceback.c b/Python/traceback.c index 8ac1bc06bb87c8..47c89e50ec7abb 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -239,8 +239,8 @@ _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, _PyInterpreterFrame_LASTI(frame->f_frame)*sizeof(_Py_CODEUNIT), + int addr = _PyInterpreterFrame_LASTI(frame->f_frame) * sizeof(_Py_CODEUNIT); + return tb_create_raw((PyTracebackObject *)tb_next, frame, addr, PyFrame_GetLineNumber(frame)); } @@ -1181,7 +1181,8 @@ dump_frame(int fd, _PyInterpreterFrame *frame) PUTS(fd, "???"); } - int lineno = PyCode_Addr2Line(code, _PyInterpreterFrame_LASTI(frame)*sizeof(_Py_CODEUNIT)); + int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); + int lineno = PyCode_Addr2Line(code, addr); PUTS(fd, ", line "); if (lineno >= 0) { _Py_DumpDecimal(fd, (size_t)lineno); From 16695dc9d8648b7ca7d3b13ff68cda6897bf828b Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 25 Mar 2022 15:42:05 -0700 Subject: [PATCH 04/12] More cleanup --- Tools/gdb/libpython.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 0a54ff2f36e017..3bc3d2f3484541 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -1015,9 +1015,9 @@ def _f_nlocalsplus(self): return self._f_special("nlocalsplus", int_from_int) def _f_lasti(self): - _Py_CODEUNIT = gdb.lookup_type("_Py_CODEUNIT") + codeunit_p = gdb.lookup_type("_Py_CODEUNIT").pointer() next_instr = self._gdbval["next_instr"] - first_instr = self._f_code().field("co_code_adaptive").cast(_Py_CODEUNIT.pointer()) + first_instr = self._f_code().field("co_code_adaptive").cast(codeunit_p) return int(next_instr - first_instr - 1) def is_entry(self): From cd1aab7bf7fe8ea59a71b25996fddf142a3aef55 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Wed, 30 Mar 2022 14:33:31 -0700 Subject: [PATCH 05/12] Move parentheses --- Include/internal/pycore_frame.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index ea2165a644f3ab..a16238179b8df3 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -55,7 +55,7 @@ typedef struct _PyInterpreterFrame { } _PyInterpreterFrame; #define _PyInterpreterFrame_LASTI(IF) \ - ((int)((IF)->next_instr - _PyCode_CODE((IF)->f_code)) - 1) + ((int)((IF)->next_instr - _PyCode_CODE((IF)->f_code) - 1)) static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { return f->localsplus + f->f_code->co_nlocalsplus; From 1d77eb30bdc2837ec1faa3761abc5c71d3e0120a Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 31 Mar 2022 01:30:06 +0000 Subject: [PATCH 06/12] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst new file mode 100644 index 00000000000000..b5d8aeb334382f --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst @@ -0,0 +1 @@ +Replace the ``f_lasti`` member of the internal ``_PyInterpreterFrame`` structure with a ``next_instr`` pointer, which reduces overhead in the main interpreter loop. The ``f_lasti`` attribute of Python-layer frame objects is preserved for backward-compatibility. From 1dd3ec5e7804564c49fe469b77a21f6139f14665 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 31 Mar 2022 11:16:10 -0700 Subject: [PATCH 07/12] Add _PyInterpreterFrame_GetLine --- Include/internal/pycore_frame.h | 1 + Modules/_tracemalloc.c | 3 +-- Objects/frameobject.c | 3 +-- Objects/genobject.c | 3 +-- Python/ceval.c | 9 +++------ Python/frame.c | 7 +++++++ Python/traceback.c | 3 +-- 7 files changed, 15 insertions(+), 14 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index a16238179b8df3..48a71e49394638 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -184,6 +184,7 @@ void _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame); _PyInterpreterFrame * _PyFrame_Push(PyThreadState *tstate, PyFunctionObject *func); +int _PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame); static inline PyGenObject *_PyFrame_GetGenerator(_PyInterpreterFrame *frame) diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index d9fb6c7255d2ff..ae09869deda704 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -308,8 +308,7 @@ static void tracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) { frame->filename = &_Py_STR(anon_unknown); - int addr = _PyInterpreterFrame_LASTI(pyframe) * sizeof(_Py_CODEUNIT); - int lineno = PyCode_Addr2Line(pyframe->f_code, addr); + int lineno = _PyInterpreterFrame_GetLine(pyframe); if (lineno < 0) { lineno = 0; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index c1c503473c2a10..b1ac73f89803c5 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -39,8 +39,7 @@ PyFrame_GetLineNumber(PyFrameObject *f) return f->f_lineno; } else { - int addr = _PyInterpreterFrame_LASTI(f->f_frame) * sizeof(_Py_CODEUNIT); - return PyCode_Addr2Line(f->f_frame->f_code, addr); + return _PyInterpreterFrame_GetLine(f->f_frame); } } diff --git a/Objects/genobject.c b/Objects/genobject.c index 16d4fd825b33c9..debbd416fe0930 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1336,8 +1336,7 @@ compute_cr_origin(int origin_depth, _PyInterpreterFrame *current_frame) frame = current_frame; for (int i = 0; i < frame_count; ++i) { PyCodeObject *code = frame->f_code; - int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); - int line = PyCode_Addr2Line(frame->f_code, addr); + int line = _PyInterpreterFrame_GetLine(frame); PyObject *frameinfo = Py_BuildValue("OiO", code->co_filename, line, code->co_name); if (!frameinfo) { diff --git a/Python/ceval.c b/Python/ceval.c index a3c52c367ae8e9..73046dad63f969 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -5505,10 +5505,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #else default: #endif - ; - int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); - int line = PyCode_Addr2Line(frame->f_code, addr); - fprintf(stderr, "XXX lineno: %d, opcode: %d\n", line, opcode); + fprintf(stderr, "XXX lineno: %d, opcode: %d\n", + _PyInterpreterFrame_GetLine(frame), opcode); _PyErr_SetString(tstate, PyExc_SystemError, "unknown opcode"); goto error; @@ -7702,8 +7700,7 @@ dtrace_function_entry(_PyInterpreterFrame *frame) PyCodeObject *code = frame->f_code; filename = PyUnicode_AsUTF8(code->co_filename); funcname = PyUnicode_AsUTF8(code->co_name); - int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); - lineno = PyCode_Addr2Line(frame->f_code, addr); + lineno = _PyInterpreterFrame_GetLine(frame); PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno); } diff --git a/Python/frame.c b/Python/frame.c index 3396ed8d2aeb0e..03aac4f0a59fcd 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -127,3 +127,10 @@ _PyFrame_Push(PyThreadState *tstate, PyFunctionObject *func) _PyFrame_InitializeSpecials(new_frame, func, NULL, code->co_nlocalsplus); return new_frame; } + +int +_PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame) +{ + int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); + return PyCode_Addr2Line(frame->f_code, addr); +} \ No newline at end of file diff --git a/Python/traceback.c b/Python/traceback.c index 47c89e50ec7abb..f99d9e97312879 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -1181,8 +1181,7 @@ dump_frame(int fd, _PyInterpreterFrame *frame) PUTS(fd, "???"); } - int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); - int lineno = PyCode_Addr2Line(code, addr); + int lineno = _PyInterpreterFrame_GetLine(frame); PUTS(fd, ", line "); if (lineno >= 0) { _Py_DumpDecimal(fd, (size_t)lineno); From 725d34c5ca1c70211b4d4d839edf1c23d10e5f20 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 31 Mar 2022 13:59:23 -0700 Subject: [PATCH 08/12] Apply feedback from PR review --- Include/internal/pycore_frame.h | 5 +++++ Objects/genobject.c | 2 +- Python/ceval.c | 14 +++++++++----- Python/frame.c | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 48a71e49394638..0db97bf7eb13ce 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -54,6 +54,11 @@ typedef struct _PyInterpreterFrame { PyObject *localsplus[1]; } _PyInterpreterFrame; +// NOTE: This is not necessarily the index of the last instruction started in +// the given frame. Rather, it is the index *prior to* the *next* instruction. +// For example, it may the offset of an inline CACHE entry, an instruction we +// just jumped over, or (in the case of a newly-created frame) a value of -1. +// It is here for mostly historical reasons. #define _PyInterpreterFrame_LASTI(IF) \ ((int)((IF)->next_instr - _PyCode_CODE((IF)->f_code) - 1)) diff --git a/Objects/genobject.c b/Objects/genobject.c index debbd416fe0930..d29ca274b7208e 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -352,7 +352,7 @@ _PyGen_yf(PyGenObject *gen) if (gen->gi_frame_state < FRAME_CLEARED) { _PyInterpreterFrame *frame = (_PyInterpreterFrame *)gen->gi_iframe; - if (_PyInterpreterFrame_LASTI(frame) < 1) { + if (gen->gi_frame_state == FRAME_CREATED) { /* Return immediately if the frame didn't start yet. SEND always come after LOAD_CONST: a code object should not start with SEND */ diff --git a/Python/ceval.c b/Python/ceval.c index 73046dad63f969..1f615a33b6f430 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2200,7 +2200,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int new_frame->localsplus[i] = NULL; } _PyFrame_SetStackPointer(frame, stack_pointer); - frame->next_instr += INLINE_CACHE_ENTRIES_BINARY_SUBSCR; + JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); + frame->next_instr = next_instr; new_frame->previous = frame; frame = cframe.current_frame = new_frame; CALL_STAT_INC(inlined_py_calls); @@ -4615,7 +4616,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto error; } _PyFrame_SetStackPointer(frame, stack_pointer); - frame->next_instr += INLINE_CACHE_ENTRIES_CALL; + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + frame->next_instr = next_instr; new_frame->previous = frame; cframe.current_frame = frame = new_frame; CALL_STAT_INC(inlined_py_calls); @@ -4720,7 +4722,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } STACK_SHRINK(2-is_meth); _PyFrame_SetStackPointer(frame, stack_pointer); - frame->next_instr += INLINE_CACHE_ENTRIES_CALL; + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + frame->next_instr = next_instr; new_frame->previous = frame; frame = cframe.current_frame = new_frame; goto start_frame; @@ -4760,7 +4763,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } STACK_SHRINK(2-is_meth); _PyFrame_SetStackPointer(frame, stack_pointer); - frame->next_instr += INLINE_CACHE_ENTRIES_CALL; + JUMPBY(INLINE_CACHE_ENTRIES_CALL); + frame->next_instr = next_instr; new_frame->previous = frame; frame = cframe.current_frame = new_frame; goto start_frame; @@ -7715,7 +7719,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, _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT)); + lineno = _PyInterpreterFrame_GetLine(frame); PyDTrace_FUNCTION_RETURN(filename, funcname, lineno); } diff --git a/Python/frame.c b/Python/frame.c index 03aac4f0a59fcd..c2da123a2bbc15 100644 --- a/Python/frame.c +++ b/Python/frame.c @@ -133,4 +133,4 @@ _PyInterpreterFrame_GetLine(_PyInterpreterFrame *frame) { int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT); return PyCode_Addr2Line(frame->f_code, addr); -} \ No newline at end of file +} From 86ed96b771f695952fcaf98ed6a3bd5f996ac347 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 31 Mar 2022 16:22:51 -0700 Subject: [PATCH 09/12] More PR review --- Include/internal/pycore_frame.h | 2 +- Objects/frameobject.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 0db97bf7eb13ce..9c9686de85f712 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -56,7 +56,7 @@ typedef struct _PyInterpreterFrame { // NOTE: This is not necessarily the index of the last instruction started in // the given frame. Rather, it is the index *prior to* the *next* instruction. -// For example, it may the offset of an inline CACHE entry, an instruction we +// For example, it may be the index of an inline CACHE entry, an instruction we // just jumped over, or (in the case of a newly-created frame) a value of -1. // It is here for mostly historical reasons. #define _PyInterpreterFrame_LASTI(IF) \ diff --git a/Objects/frameobject.c b/Objects/frameobject.c index b1ac73f89803c5..3f5eb200e87a99 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -888,7 +888,7 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg) assert(_PyOpcode_Deopt[opcode] == opcode); int check_oparg = 0; for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code); - instruction < frame->next_instr; instruction++) + instruction < frame->next_instr - 1; instruction++) { int check_opcode = _PyOpcode_Deopt[_Py_OPCODE(*instruction)]; check_oparg |= _Py_OPARG(*instruction); From 5251e0a9c6355f2f0f9ebc78b3102b25334a6598 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 31 Mar 2022 16:58:04 -0700 Subject: [PATCH 10/12] next_instr -> prev_instr --- Include/internal/pycore_frame.h | 16 +++++++--------- Objects/frameobject.c | 8 ++++---- Objects/genobject.c | 8 ++++---- Python/ceval.c | 22 +++++++++++----------- Tools/gdb/libpython.py | 4 ++-- 5 files changed, 28 insertions(+), 30 deletions(-) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 9c9686de85f712..5e3e4dfb570754 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -47,20 +47,18 @@ typedef struct _PyInterpreterFrame { PyCodeObject *f_code; /* Strong reference */ PyFrameObject *frame_obj; /* Strong reference, may be NULL */ struct _PyInterpreterFrame *previous; - _Py_CODEUNIT *next_instr; + // NOTE: This is not necessarily the last instruction started in the given + // frame. Rather, it is the code unit *prior to* the *next* instruction. For + // example, it may be an inline CACHE entry, an instruction we just jumped + // over, or (in the case of a newly-created frame) a totally invalid value: + _Py_CODEUNIT *prev_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; - -// NOTE: This is not necessarily the index of the last instruction started in -// the given frame. Rather, it is the index *prior to* the *next* instruction. -// For example, it may be the index of an inline CACHE entry, an instruction we -// just jumped over, or (in the case of a newly-created frame) a value of -1. -// It is here for mostly historical reasons. #define _PyInterpreterFrame_LASTI(IF) \ - ((int)((IF)->next_instr - _PyCode_CODE((IF)->f_code) - 1)) + ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code))) static inline PyObject **_PyFrame_Stackbase(_PyInterpreterFrame *f) { return f->localsplus + f->f_code->co_nlocalsplus; @@ -100,7 +98,7 @@ _PyFrame_InitializeSpecials( frame->f_locals = Py_XNewRef(locals); frame->stacktop = nlocalsplus; frame->frame_obj = NULL; - frame->next_instr = _PyCode_CODE(frame->f_code); + frame->prev_instr = _PyCode_CODE(frame->f_code) - 1; frame->is_entry = false; frame->owner = FRAME_OWNED_BY_THREAD; } diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 3f5eb200e87a99..d8bd25d1440d92 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -430,7 +430,7 @@ _PyFrame_GetState(PyFrameObject *frame) if (_PyInterpreterFrame_LASTI(frame->f_frame) < 0) { return FRAME_CREATED; } - switch (_PyOpcode_Deopt[_Py_OPCODE(frame->f_frame->next_instr[-1])]) + switch (_PyOpcode_Deopt[_Py_OPCODE(*frame->f_frame->prev_instr)]) { case COPY_FREE_VARS: case MAKE_CELL: @@ -605,7 +605,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->next_instr = _PyCode_CODE(f->f_frame->f_code) + best_addr + 1; + f->f_frame->prev_instr = _PyCode_CODE(f->f_frame->f_code) + best_addr; return 0; } @@ -888,7 +888,7 @@ _PyFrame_OpAlreadyRan(_PyInterpreterFrame *frame, int opcode, int oparg) assert(_PyOpcode_Deopt[opcode] == opcode); int check_oparg = 0; for (_Py_CODEUNIT *instruction = _PyCode_CODE(frame->f_code); - instruction < frame->next_instr - 1; instruction++) + instruction < frame->prev_instr; instruction++) { int check_opcode = _PyOpcode_Deopt[_Py_OPCODE(*instruction)]; check_oparg |= _Py_OPARG(*instruction); @@ -934,7 +934,7 @@ _PyFrame_FastToLocalsWithError(_PyInterpreterFrame *frame) { frame->localsplus[offset + i] = o; } // COPY_FREE_VARS doesn't have inline CACHEs, either: - frame->next_instr = _PyCode_CODE(frame->f_code) + 1; + frame->prev_instr = _PyCode_CODE(frame->f_code); } for (int i = 0; i < co->co_nlocalsplus; i++) { _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i); diff --git a/Objects/genobject.c b/Objects/genobject.c index d29ca274b7208e..762f8d580a619a 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -359,7 +359,7 @@ _PyGen_yf(PyGenObject *gen) assert(_Py_OPCODE(_PyCode_CODE(gen->gi_code)[0]) != SEND); return NULL; } - _Py_CODEUNIT next = *frame->next_instr; + _Py_CODEUNIT next = frame->prev_instr[1]; if (_PyOpcode_Deopt[_Py_OPCODE(next)] != RESUME || _Py_OPARG(next) < 2) { /* Not in a yield from */ @@ -489,9 +489,9 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, /* Termination repetition of SEND loop */ assert(_PyInterpreterFrame_LASTI(frame) >= 0); /* Backup to SEND */ - assert(_Py_OPCODE(frame->next_instr[-2]) == SEND); - int jump = _Py_OPARG(frame->next_instr[-2]); - frame->next_instr += jump - 1; + assert(_Py_OPCODE(frame->prev_instr[-1]) == SEND); + int jump = _Py_OPARG(frame->prev_instr[-1]); + frame->prev_instr += jump - 1; if (_PyGen_FetchStopIterationValue(&val) == 0) { ret = gen_send(gen, val); Py_DECREF(val); diff --git a/Python/ceval.c b/Python/ceval.c index 1f615a33b6f430..2766a29aadac13 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1247,13 +1247,13 @@ eval_frame_handle_pending(PyThreadState *tstate) #ifdef Py_STATS #define INSTRUCTION_START(op) \ do { \ - frame->next_instr = ++next_instr; \ + frame->prev_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->next_instr = ++next_instr) +#define INSTRUCTION_START(op) (frame->prev_instr = next_instr++) #endif #if USE_COMPUTED_GOTOS @@ -1644,7 +1644,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } \ assert(_PyInterpreterFrame_LASTI(frame) >= -1); \ /* Jump back to the last instruction executed... */ \ - next_instr = frame->next_instr; \ + next_instr = frame->prev_instr + 1; \ stack_pointer = _PyFrame_GetStackPointer(frame); \ /* Set stackdepth to -1. \ Update when returning or calling trace function. \ @@ -2201,7 +2201,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } _PyFrame_SetStackPointer(frame, stack_pointer); JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR); - frame->next_instr = next_instr; + frame->prev_instr = next_instr - 1; new_frame->previous = frame; frame = cframe.current_frame = new_frame; CALL_STAT_INC(inlined_py_calls); @@ -2605,7 +2605,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int if (oparg) { PyObject *lasti = PEEK(oparg + 1); if (PyLong_Check(lasti)) { - frame->next_instr = first_instr + PyLong_AsLong(lasti) + 1; + frame->prev_instr = first_instr + PyLong_AsLong(lasti); assert(!_PyErr_Occurred(tstate)); } else { @@ -4617,7 +4617,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } _PyFrame_SetStackPointer(frame, stack_pointer); JUMPBY(INLINE_CACHE_ENTRIES_CALL); - frame->next_instr = next_instr; + frame->prev_instr = next_instr - 1; new_frame->previous = frame; cframe.current_frame = frame = new_frame; CALL_STAT_INC(inlined_py_calls); @@ -4723,7 +4723,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int STACK_SHRINK(2-is_meth); _PyFrame_SetStackPointer(frame, stack_pointer); JUMPBY(INLINE_CACHE_ENTRIES_CALL); - frame->next_instr = next_instr; + frame->prev_instr = next_instr - 1; new_frame->previous = frame; frame = cframe.current_frame = new_frame; goto start_frame; @@ -4764,7 +4764,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int STACK_SHRINK(2-is_meth); _PyFrame_SetStackPointer(frame, stack_pointer); JUMPBY(INLINE_CACHE_ENTRIES_CALL); - frame->next_instr = next_instr; + frame->prev_instr = next_instr - 1; new_frame->previous = frame; frame = cframe.current_frame = new_frame; goto start_frame; @@ -5454,7 +5454,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int { if (tstate->tracing == 0) { int instr_prev = _PyInterpreterFrame_LASTI(frame); - frame->next_instr = next_instr + 1; + frame->prev_instr = next_instr; TRACING_NEXTOPARG(); switch(opcode) { case COPY_FREE_VARS: @@ -5492,7 +5492,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto error; } /* Reload possibly changed frame fields */ - next_instr = frame->next_instr - 1; + next_instr = frame->prev_instr; stack_pointer = _PyFrame_GetStackPointer(frame); frame->stacktop = -1; @@ -6772,7 +6772,7 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, (_PyInterpreterFrame_LASTI(frame) < instr_prev && // SEND has no quickened forms, so no need to use _PyOpcode_Deopt // here: - _Py_OPCODE(frame->next_instr[-1]) != SEND); + _Py_OPCODE(*frame->prev_instr) != SEND); if (trace) { result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } diff --git a/Tools/gdb/libpython.py b/Tools/gdb/libpython.py index 3bc3d2f3484541..4f7a8bca5fd786 100755 --- a/Tools/gdb/libpython.py +++ b/Tools/gdb/libpython.py @@ -1016,9 +1016,9 @@ def _f_nlocalsplus(self): def _f_lasti(self): codeunit_p = gdb.lookup_type("_Py_CODEUNIT").pointer() - next_instr = self._gdbval["next_instr"] + prev_instr = self._gdbval["prev_instr"] first_instr = self._f_code().field("co_code_adaptive").cast(codeunit_p) - return int(next_instr - first_instr - 1) + return int(prev_instr - first_instr) def is_entry(self): return self._f_special("is_entry", bool) From 90a4c5ab33b88a073d0f279f0791df2a346870c4 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 31 Mar 2022 17:19:54 -0700 Subject: [PATCH 11/12] Fix whitespace --- Include/internal/pycore_frame.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h index 5e3e4dfb570754..49bdc6324ca363 100644 --- a/Include/internal/pycore_frame.h +++ b/Include/internal/pycore_frame.h @@ -57,6 +57,7 @@ typedef struct _PyInterpreterFrame { char owner; PyObject *localsplus[1]; } _PyInterpreterFrame; + #define _PyInterpreterFrame_LASTI(IF) \ ((int)((IF)->prev_instr - _PyCode_CODE((IF)->f_code))) From 670b94b46c44dce0ffba713f413f5b6a2d400c67 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Wed, 6 Apr 2022 13:13:35 -0700 Subject: [PATCH 12/12] Update NEWS --- .../Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst b/Misc/NEWS.d/next/Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst index b5d8aeb334382f..01e6c883924588 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-03-31-01-30-03.bpo-47177.fQqaov.rst @@ -1 +1 @@ -Replace the ``f_lasti`` member of the internal ``_PyInterpreterFrame`` structure with a ``next_instr`` pointer, which reduces overhead in the main interpreter loop. The ``f_lasti`` attribute of Python-layer frame objects is preserved for backward-compatibility. +Replace the ``f_lasti`` member of the internal ``_PyInterpreterFrame`` structure with a ``prev_instr`` pointer, which reduces overhead in the main interpreter loop. The ``f_lasti`` attribute of Python-layer frame objects is preserved for backward-compatibility.