mirror of https://github.com/python/cpython
GH-93516: Store offset of first traceable instruction in code object (GH-93769)
This commit is contained in:
parent
2bf74753c1
commit
3cd1a5d3ec
|
@ -89,6 +89,7 @@ typedef uint16_t _Py_CODEUNIT;
|
|||
PyObject *co_linetable; /* bytes object that holds location info */ \
|
||||
PyObject *co_weakreflist; /* to support weakrefs to code objects */ \
|
||||
void *_co_code; /* cached co_code object/attribute */ \
|
||||
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. */ \
|
||||
|
|
|
@ -177,7 +177,7 @@ def_op('LOAD_CLASSDEREF', 148)
|
|||
hasfree.append(148)
|
||||
def_op('COPY_FREE_VARS', 149)
|
||||
def_op('YIELD_VALUE', 150)
|
||||
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)
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Store offset of first traceable instruction in code object to avoid having
|
||||
to recompute it for each instruction when tracing.
|
|
@ -339,6 +339,12 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
|
|||
co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
|
||||
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
|
||||
|
|
|
@ -5568,57 +5568,47 @@ handle_eval_breaker:
|
|||
case DO_TRACING:
|
||||
#endif
|
||||
{
|
||||
if (tstate->tracing == 0) {
|
||||
if (tstate->tracing == 0 &&
|
||||
INSTR_OFFSET() >= frame->f_code->_co_firsttraceable
|
||||
) {
|
||||
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 (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);
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
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();
|
||||
|
@ -6855,13 +6845,8 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
|
|||
then call the trace function if we're tracing source lines.
|
||||
*/
|
||||
initialize_trace_info(&tstate->trace_info, frame);
|
||||
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 {
|
||||
|
|
|
@ -20,6 +20,9 @@ from generate_global_objects import get_identifiers_and_strings
|
|||
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)
|
||||
|
||||
|
@ -267,6 +270,10 @@ class Printer:
|
|||
self.write(f".co_qualname = {co_qualname},")
|
||||
self.write(f".co_linetable = {co_linetable},")
|
||||
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})")
|
||||
|
|
Loading…
Reference in New Issue