diff --git a/Doc/data/python3.11.abi b/Doc/data/python3.11.abi
index 79b3ca3995c246..98cdaf9524bbc3 100644
--- a/Doc/data/python3.11.abi
+++ b/Doc/data/python3.11.abi
@@ -5858,122 +5858,125 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
@@ -7454,93 +7457,93 @@
-
-
-
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -7594,8 +7597,8 @@
-
-
+
+
@@ -11172,32 +11175,32 @@
-
+
-
-
+
+
-
-
+
+
-
+
-
-
-
+
+
+
-
+
-
+
@@ -11211,33 +11214,33 @@
-
-
+
+
-
+
-
+
-
-
+
+
-
+
-
+
-
+
-
-
-
+
+
+
@@ -11363,43 +11366,43 @@
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -14919,7 +14922,7 @@
-
+
diff --git a/Include/cpython/code.h b/Include/cpython/code.h
index 66cf4eccb8fcc9..ef8c6422046dc7 100644
--- a/Include/cpython/code.h
+++ b/Include/cpython/code.h
@@ -91,6 +91,7 @@ typedef uint16_t _Py_CODEUNIT;
PyObject *co_weakreflist; /* to support weakrefs to code objects */ \
PyObject *_co_code; /* cached co_code object/attribute */ \
char *_co_linearray; /* array of line offsets */ \
+ int _co_firsttraceable; /* index of first traceable instruction */ \
/* Scratch space for extra data relating to the code object. \
Type is a void* to keep the format private in codeobject.c to force \
people to go through the proper APIs. */ \
diff --git a/Lib/opcode.py b/Lib/opcode.py
index 310582874dc8f0..bc3c02af2bccb3 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -175,7 +175,7 @@ def jabs_op(name, op):
hasfree.append(148)
def_op('COPY_FREE_VARS', 149)
-def_op('RESUME', 151)
+def_op('RESUME', 151) # This must be kept in sync with deepfreeze.py
def_op('MATCH_CLASS', 152)
def_op('FORMAT_VALUE', 155)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-06-13-13-55-34.gh-issue-93516.HILrDl.rst b/Misc/NEWS.d/next/Core and Builtins/2022-06-13-13-55-34.gh-issue-93516.HILrDl.rst
new file mode 100644
index 00000000000000..a324c2dbcbe8a6
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-06-13-13-55-34.gh-issue-93516.HILrDl.rst
@@ -0,0 +1,2 @@
+Store offset of first traceable instruction in code object to avoid having
+to recompute it for each instruction when tracing.
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 8b9ca890431c6c..fddb42425ba068 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -341,6 +341,12 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
co->_co_linearray = NULL;
memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code),
PyBytes_GET_SIZE(con->code));
+ int entry_point = 0;
+ while (entry_point < Py_SIZE(co) &&
+ _Py_OPCODE(_PyCode_CODE(co)[entry_point]) != RESUME) {
+ entry_point++;
+ }
+ co->_co_firsttraceable = entry_point;
}
static int
diff --git a/Python/ceval.c b/Python/ceval.c
index 763187a8317af4..2d794837ce3d7e 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -5608,57 +5608,51 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
case DO_TRACING:
#endif
{
- if (tstate->tracing == 0) {
+ if (tstate->tracing == 0 &&
+ INSTR_OFFSET() >= frame->f_code->_co_firsttraceable
+ ) {
+ assert(
+ _PyOpcode_Deopt[first_instr[frame->f_code->_co_firsttraceable]]
+ == RESUME
+ );
int instr_prev = _PyInterpreterFrame_LASTI(frame);
frame->prev_instr = next_instr;
TRACING_NEXTOPARG();
- switch(opcode) {
- case COPY_FREE_VARS:
- case MAKE_CELL:
- case RETURN_GENERATOR:
- /* Frame not fully initialized */
- break;
- case RESUME:
- if (oparg < 2) {
- CHECK_EVAL_BREAKER();
- }
- /* Call tracing */
- TRACE_FUNCTION_ENTRY();
- DTRACE_FUNCTION_ENTRY();
- break;
- case POP_TOP:
- if (_Py_OPCODE(next_instr[-1]) == RETURN_GENERATOR) {
- /* Frame not fully initialized */
- break;
- }
- /* fall through */
- default:
- /* line-by-line tracing support */
- if (PyDTrace_LINE_ENABLED()) {
- maybe_dtrace_line(frame, &tstate->trace_info, instr_prev);
- }
-
- if (cframe.use_tracing &&
- tstate->c_tracefunc != NULL && !tstate->tracing) {
- int err;
- /* see maybe_call_line_trace()
- for expository comments */
- _PyFrame_SetStackPointer(frame, stack_pointer);
-
- err = maybe_call_line_trace(tstate->c_tracefunc,
- tstate->c_traceobj,
- tstate, frame, instr_prev);
- if (err) {
- /* trace function raised an exception */
- next_instr++;
- goto error;
- }
- /* Reload possibly changed frame fields */
- next_instr = frame->prev_instr;
+ if (opcode == RESUME) {
+ if (oparg < 2) {
+ CHECK_EVAL_BREAKER();
+ }
+ /* Call tracing */
+ TRACE_FUNCTION_ENTRY();
+ DTRACE_FUNCTION_ENTRY();
+ }
+ else {
+ /* line-by-line tracing support */
+ if (PyDTrace_LINE_ENABLED()) {
+ maybe_dtrace_line(frame, &tstate->trace_info, instr_prev);
+ }
- stack_pointer = _PyFrame_GetStackPointer(frame);
- frame->stacktop = -1;
+ if (cframe.use_tracing &&
+ tstate->c_tracefunc != NULL && !tstate->tracing) {
+ int err;
+ /* see maybe_call_line_trace()
+ for expository comments */
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+
+ err = maybe_call_line_trace(tstate->c_tracefunc,
+ tstate->c_traceobj,
+ tstate, frame, instr_prev);
+ if (err) {
+ /* trace function raised an exception */
+ next_instr++;
+ goto error;
}
+ /* Reload possibly changed frame fields */
+ next_instr = frame->prev_instr;
+
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ frame->stacktop = -1;
+ }
}
}
TRACING_NEXTOPARG();
@@ -6896,13 +6890,8 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
if (_PyCode_InitLineArray(frame->f_code)) {
return -1;
}
- int entry_point = 0;
- _Py_CODEUNIT *code = _PyCode_CODE(frame->f_code);
- while (_PyOpcode_Deopt[_Py_OPCODE(code[entry_point])] != RESUME) {
- entry_point++;
- }
int lastline;
- if (instr_prev <= entry_point) {
+ if (instr_prev <= frame->f_code->_co_firsttraceable) {
lastline = -1;
}
else {
diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py
index 5aca79a722e11e..5a64c1ec2e61f7 100644
--- a/Tools/scripts/deepfreeze.py
+++ b/Tools/scripts/deepfreeze.py
@@ -22,6 +22,9 @@
verbose = False
identifiers, strings = get_identifiers_and_strings()
+# This must be kept in sync with opcode.py
+RESUME = 151
+
def isprintable(b: bytes) -> bool:
return all(0x20 <= c < 0x7f for c in b)
@@ -284,6 +287,10 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
self.write(f"._co_code = NULL,")
self.write("._co_linearray = NULL,")
self.write(f".co_code_adaptive = {co_code_adaptive},")
+ for i, op in enumerate(code.co_code[::2]):
+ if op == RESUME:
+ self.write(f"._co_firsttraceable = {i},")
+ break
name_as_code = f"(PyCodeObject *)&{name}"
self.deallocs.append(f"_PyStaticCode_Dealloc({name_as_code});")
self.interns.append(f"_PyStaticCode_InternStrings({name_as_code})")