summaryrefslogtreecommitdiffstats
path: root/Objects/codeobject.c
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2025-07-15 15:10:37 (GMT)
committerGitHub <noreply@github.com>2025-07-15 15:10:37 (GMT)
commit9ae74e94a06865aee96827838ce16c8924cbe86f (patch)
tree71932366c8f66e7d486570a471fd147d48cbf09b /Objects/codeobject.c
parentc939963b53600062f0978c99559e22ab39135402 (diff)
downloadcpython-9ae74e94a06865aee96827838ce16c8924cbe86f.zip
cpython-9ae74e94a06865aee96827838ce16c8924cbe86f.tar.gz
cpython-9ae74e94a06865aee96827838ce16c8924cbe86f.tar.bz2
[3.14] gh-136396: Include instrumentation when creating new copies of the bytecode (GH-136525) (GH-136657)
Previously, we assumed that instrumentation would happen for all copies of the bytecode if the instrumentation version on the code object didn't match the per-interpreter instrumentation version. That assumption was incorrect: instrumentation will exit early if there are no new "events," even if there is an instrumentation version mismatch. To fix this, include the instrumented opcodes when creating new copies of the bytecode, rather than replacing them with their uninstrumented variants. I don't think we have to worry about races between instrumentation and creating new copies of the bytecode: instrumentation and new bytecode creation cannot happen concurrently. Instrumentation requires that either the world is stopped or the code object's per-object lock is held and new bytecode creation requires holding the code object's per-object lock. (cherry picked from commit d995922198304a6de19ac1bec3e36d1e886d8468) Co-authored-by: mpage <mpage@meta.com> Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Diffstat (limited to 'Objects/codeobject.c')
-rw-r--r--Objects/codeobject.c19
1 files changed, 18 insertions, 1 deletions
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index ba178abc..42e0216 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -3330,12 +3330,29 @@ _PyCodeArray_New(Py_ssize_t size)
return arr;
}
+// Get the underlying code unit, leaving instrumentation
+static _Py_CODEUNIT
+deopt_code_unit(PyCodeObject *code, int i)
+{
+ _Py_CODEUNIT *src_instr = _PyCode_CODE(code) + i;
+ _Py_CODEUNIT inst = {
+ .cache = FT_ATOMIC_LOAD_UINT16_RELAXED(*(uint16_t *)src_instr)};
+ int opcode = inst.op.code;
+ if (opcode < MIN_INSTRUMENTED_OPCODE) {
+ inst.op.code = _PyOpcode_Deopt[opcode];
+ assert(inst.op.code < MIN_SPECIALIZED_OPCODE);
+ }
+ // JIT should not be enabled with free-threading
+ assert(inst.op.code != ENTER_EXECUTOR);
+ return inst;
+}
+
static void
copy_code(_Py_CODEUNIT *dst, PyCodeObject *co)
{
int code_len = (int) Py_SIZE(co);
for (int i = 0; i < code_len; i += _PyInstruction_GetLength(co, i)) {
- dst[i] = _Py_GetBaseCodeUnit(co, i);
+ dst[i] = deopt_code_unit(co, i);
}
_PyCode_Quicken(dst, code_len, 1);
}