summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2024-05-06 21:21:06 (GMT)
committerGitHub <noreply@github.com>2024-05-06 21:21:06 (GMT)
commit616b745b89a52a1d27123107718f85e65918afdc (patch)
tree3e0c5691ed679c3d0008f87da0e8661077934a6e
parent00d913c6718aa365027c6dcf850e8f40731e54fc (diff)
downloadcpython-616b745b89a52a1d27123107718f85e65918afdc.zip
cpython-616b745b89a52a1d27123107718f85e65918afdc.tar.gz
cpython-616b745b89a52a1d27123107718f85e65918afdc.tar.bz2
GH-115709: Invalidate executors when a local variable is changed via frame.f_locals (#118639)
Also fix unrelated assert in debug Tier2/JIT builds.
-rw-r--r--Include/cpython/optimizer.h12
-rw-r--r--Lib/test/test_capi/test_opt.py13
-rw-r--r--Objects/frameobject.c3
-rw-r--r--Python/bytecodes.c3
-rw-r--r--Python/generated_cases.c.h3
5 files changed, 30 insertions, 4 deletions
diff --git a/Include/cpython/optimizer.h b/Include/cpython/optimizer.h
index 744a272..5f218d7 100644
--- a/Include/cpython/optimizer.h
+++ b/Include/cpython/optimizer.h
@@ -141,9 +141,6 @@ void _Py_ExecutorDetach(_PyExecutorObject *);
void _Py_BloomFilter_Init(_PyBloomFilter *);
void _Py_BloomFilter_Add(_PyBloomFilter *bloom, void *obj);
PyAPI_FUNC(void) _Py_Executor_DependsOn(_PyExecutorObject *executor, void *obj);
-PyAPI_FUNC(void) _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation);
-PyAPI_FUNC(void) _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation);
-
/* For testing */
PyAPI_FUNC(PyObject *)PyUnstable_Optimizer_NewCounter(void);
PyAPI_FUNC(PyObject *)PyUnstable_Optimizer_NewUOpOptimizer(void);
@@ -151,6 +148,15 @@ PyAPI_FUNC(PyObject *)PyUnstable_Optimizer_NewUOpOptimizer(void);
#define _Py_MAX_ALLOWED_BUILTINS_MODIFICATIONS 3
#define _Py_MAX_ALLOWED_GLOBALS_MODIFICATIONS 6
+#ifdef _Py_TIER2
+PyAPI_FUNC(void) _Py_Executors_InvalidateDependency(PyInterpreterState *interp, void *obj, int is_invalidation);
+PyAPI_FUNC(void) _Py_Executors_InvalidateAll(PyInterpreterState *interp, int is_invalidation);
+#else
+# define _Py_Executors_InvalidateDependency(A, B, C) ((void)0)
+# define _Py_Executors_InvalidateAll(A, B) ((void)0)
+#endif
+
+
#ifdef __cplusplus
}
#endif
diff --git a/Lib/test/test_capi/test_opt.py b/Lib/test/test_capi/test_opt.py
index 6e5b626..0491ff9 100644
--- a/Lib/test/test_capi/test_opt.py
+++ b/Lib/test/test_capi/test_opt.py
@@ -1321,5 +1321,18 @@ class TestUopsOptimization(unittest.TestCase):
self.assertIsNotNone(ex)
self.assertIn("_FOR_ITER_GEN_FRAME", get_opnames(ex))
+ def test_modified_local_is_seen_by_optimized_code(self):
+ l = sys._getframe().f_locals
+ a = 1
+ s = 0
+ for j in range(1 << 10):
+ a + a
+ l["xa"[j >> 9]] = 1.0
+ s += a
+ self.assertIs(type(a), float)
+ self.assertIs(type(s), float)
+ self.assertEqual(s, 1024.0)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 869cdec..26a04cb 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -148,8 +148,9 @@ framelocalsproxy_setitem(PyObject *self, PyObject *key, PyObject *value)
if (PyUnicode_CheckExact(key)) {
int i = framelocalsproxy_getkeyindex(frame, key, false);
if (i >= 0) {
- _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
+ _Py_Executors_InvalidateDependency(PyInterpreterState_Get(), co, 1);
+ _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
PyObject *oldvalue = fast[i];
PyObject *cell = NULL;
if (kind == CO_FAST_FREE) {
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index b2a0dc0..b2ddec9 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2424,6 +2424,9 @@ dummy_func(
opcode = executor->vm_data.opcode;
oparg = (oparg & ~255) | executor->vm_data.oparg;
next_instr = this_instr;
+ if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) {
+ PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter);
+ }
DISPATCH_GOTO();
}
tstate->previous_executor = Py_None;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 87098b0..d3126b0 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -2673,6 +2673,9 @@
opcode = executor->vm_data.opcode;
oparg = (oparg & ~255) | executor->vm_data.oparg;
next_instr = this_instr;
+ if (_PyOpcode_Caches[_PyOpcode_Deopt[opcode]]) {
+ PAUSE_ADAPTIVE_COUNTER(this_instr[1].counter);
+ }
DISPATCH_GOTO();
}
tstate->previous_executor = Py_None;