From 4a8e2fa69b98177d23eca93b0c784550e3f54945 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 13 Jun 2022 13:56:30 +0100 Subject: [PATCH 1/6] 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 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/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..658295de6140bc 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -341,6 +341,11 @@ 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 (_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..00fb02718d8a37 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -5608,57 +5608,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(); @@ -6896,13 +6886,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..b02e423f5e9da6 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -11,6 +11,7 @@ import collections import contextlib import os +import opcode import re import time import types @@ -22,6 +23,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) @@ -284,6 +288,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})") From 71dd6c84fa29f75f2cd62075d5baf7b9df5b3f03 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 13 Jun 2022 18:13:38 +0100 Subject: [PATCH 2/6] 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 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/Tools/scripts/deepfreeze.py b/Tools/scripts/deepfreeze.py index b02e423f5e9da6..5a64c1ec2e61f7 100644 --- a/Tools/scripts/deepfreeze.py +++ b/Tools/scripts/deepfreeze.py @@ -11,7 +11,6 @@ import collections import contextlib import os -import opcode import re import time import types @@ -23,8 +22,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 588d5feb791a82045cb1f59e4cc9e0ee9b0f9c43 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Mon, 13 Jun 2022 18:33:05 +0100 Subject: [PATCH 3/6] 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 658295de6140bc..99ca72f9822115 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -342,7 +342,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 643a6146509315ef583f4dbcb61628bf5ad88f84 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 14 Jun 2022 10:29:36 +0100 Subject: [PATCH 4/6] 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 99ca72f9822115..fddb42425ba068 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -342,8 +342,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; From fe6a1d3ce5d81d41635ad4dab4577d14cd8f98a9 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 28 Jun 2022 13:52:28 +0100 Subject: [PATCH 5/6] Assert that _co_firsttraceable is a RESUME --- Python/ceval.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Python/ceval.c b/Python/ceval.c index 00fb02718d8a37..2d794837ce3d7e 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -5611,6 +5611,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int 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(); From a0ced7127d4ca6dc9bcf79f3ed9c33720a0e1b08 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Tue, 28 Jun 2022 14:08:58 +0100 Subject: [PATCH 6/6] Regen ABI doc. --- Doc/data/python3.11.abi | 317 ++++++++++++++++++++-------------------- 1 file changed, 160 insertions(+), 157 deletions(-) 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 @@ - + 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