GH-93516: Store offset of first traceable instruction in code object (GH-93769)

This commit is contained in:
Mark Shannon 2022-06-14 11:09:30 +01:00 committed by GitHub
parent 2bf74753c1
commit 3cd1a5d3ec
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 52 deletions

View file

@ -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. */ \

View file

@ -177,7 +177,7 @@ def jabs_op(name, op):
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)

View file

@ -0,0 +1,2 @@
Store offset of first traceable instruction in code object to avoid having
to recompute it for each instruction when tracing.

View file

@ -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

View file

@ -5568,57 +5568,47 @@ _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
) {
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 {

View file

@ -20,6 +20,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)
@ -267,6 +270,10 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
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})")