From cc44d3bac8760d542a9fdf282347ae1e8013d271 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 13 Jun 2022 13:56:30 +0100 Subject: [PATCH 1/4] Store offset of first traceable instruction to avoid having to recompute it all the time when tracing. --- Include/cpython/code.h | 1 + ...2-06-13-13-55-34.gh-issue-93516.HILrDl.rst | 2 + Objects/codeobject.c | 5 ++ Python/ceval.c | 89 ++++++++----------- Tools/scripts/deepfreeze.py | 8 ++ 5 files changed, 53 insertions(+), 52 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-06-13-13-55-34.gh-issue-93516.HILrDl.rst diff --git a/Include/cpython/code.h b/Include/cpython/code.h index f544ea87406e25..1812617d3c3067 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -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. */ \ 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 2a2f132a6ef624..a63db9e1dd51cb 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -339,6 +339,11 @@ 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 (_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 0e8186347cd895..341d1d23ad99ea 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -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(); @@ -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 { diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py index ac2076708a156f..09ebb1c42241de 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -9,6 +9,7 @@ import collections import contextlib import os +import opcode import re import time import types @@ -20,6 +21,9 @@ verbose = False identifiers, strings = get_identifiers_and_strings() +RESUME = opcode.opmap["RESUME"] +del opcode + def isprintable(b: bytes) -> bool: return all(0x20 <= c < 0x7f for c in b) @@ -267,6 +271,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})") From 4af267e3e943d35f48e7ebc1b3588d9e74cc7fad Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 13 Jun 2022 18:13:38 +0100 Subject: [PATCH 2/4] Hardcode RESUME opcode in deepfreeze, to break dependency on exact version of Python used. --- Lib/opcode.py | 2 +- Tools/scripts/deepfreeze.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Lib/opcode.py b/Lib/opcode.py index 0996cc7eb0f6cd..8ae997e4b6bc6f 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -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) diff --git a/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py index 09ebb1c42241de..443fcf2274909c 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -9,7 +9,6 @@ import collections import contextlib import os -import opcode import re import time import types @@ -21,8 +20,8 @@ verbose = False identifiers, strings = get_identifiers_and_strings() -RESUME = opcode.opmap["RESUME"] -del opcode +# 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) From ea8bea24bf8699767c0736b029a8ee303060f9dc Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 13 Jun 2022 18:33:05 +0100 Subject: [PATCH 3/4] Handle empty code objects, and other invalid code, gracefully. --- Objects/codeobject.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index a63db9e1dd51cb..0d4b85a07935c6 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -340,7 +340,8 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code), PyBytes_GET_SIZE(con->code)); int entry_point = 0; - while (_Py_OPCODE(_PyCode_CODE(co)[entry_point]) != RESUME) { + while (_Py_OPCODE(_PyCode_CODE(co)[entry_point]) != RESUME && + entry_point < Py_SIZE(co)) { entry_point++; } co->_co_firsttraceable = entry_point; From a3ad25914ca877b1a121ccfaa79c63c3ec45738b Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 14 Jun 2022 10:29:36 +0100 Subject: [PATCH 4/4] Check bounds before data --- Objects/codeobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 0d4b85a07935c6..8ac4e9914f8887 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -340,8 +340,8 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con) memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code), PyBytes_GET_SIZE(con->code)); int entry_point = 0; - while (_Py_OPCODE(_PyCode_CODE(co)[entry_point]) != RESUME && - entry_point < Py_SIZE(co)) { + while (entry_point < Py_SIZE(co) && + _Py_OPCODE(_PyCode_CODE(co)[entry_point]) != RESUME) { entry_point++; } co->_co_firsttraceable = entry_point; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy