Skip to content

Commit

Permalink
GH-93516: Store offset of first traceable instruction in code object (G…
Browse files Browse the repository at this point in the history
  • Loading branch information
markshannon authored Jun 14, 2022
1 parent 2bf7475 commit 3cd1a5d
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 53 deletions.
1 change: 1 addition & 0 deletions Include/cpython/code.h
Original file line number Diff line number Diff line change
Expand Up @@ -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. */ \
Expand Down
2 changes: 1 addition & 1 deletion Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Store offset of first traceable instruction in code object to avoid having
to recompute it for each instruction when tracing.
6 changes: 6 additions & 0 deletions Objects/codeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
89 changes: 37 additions & 52 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 (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();
Expand Down Expand Up @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions Tools/scripts/deepfreeze.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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})")
Expand Down

0 comments on commit 3cd1a5d

Please sign in to comment.