]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-107265: Remove all ENTER_EXECUTOR when execute _Py_Instrument (gh-108539)
authorDong-hee Na <donghee.na@python.org>
Thu, 7 Sep 2023 00:53:54 +0000 (09:53 +0900)
committerGitHub <noreply@github.com>
Thu, 7 Sep 2023 00:53:54 +0000 (09:53 +0900)
Include/internal/pycore_code.h
Lib/test/test_monitoring.py
Objects/codeobject.c
Python/instrumentation.c

index 7c6629074758da780527e5df61129ee7a96b5a90..b3f480c72041729bb14835176c9776b728cd822f 100644 (file)
@@ -233,6 +233,9 @@ extern void _PyLineTable_InitAddressRange(
 extern int _PyLineTable_NextAddressRange(PyCodeAddressRange *range);
 extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range);
 
+/** API for executors */
+extern void _PyCode_Clear_Executors(PyCodeObject *code);
+
 #define ENABLE_SPECIALIZATION 1
 
 /* Specialization functions */
index 95fe8d03b0b29a1b2d4be4dde5eb8c5f26b6c53e..8a7d300b734dcc76e0128c590b6868b24acbb7b4 100644 (file)
@@ -1718,3 +1718,31 @@ class TestRegressions(MonitoringTestBase, unittest.TestCase):
             make_foo_optimized_then_set_event()
         finally:
             sys.monitoring.set_events(TEST_TOOL, 0)
+
+
+class TestOptimizer(MonitoringTestBase, unittest.TestCase):
+
+    def setUp(self):
+        import _testinternalcapi
+        self.old_opt = _testinternalcapi.get_optimizer()
+        opt = _testinternalcapi.get_counter_optimizer()
+        _testinternalcapi.set_optimizer(opt)
+        super(TestOptimizer, self).setUp()
+
+    def tearDown(self):
+        import _testinternalcapi
+        super(TestOptimizer, self).tearDown()
+        _testinternalcapi.set_optimizer(self.old_opt)
+
+    def test_for_loop(self):
+        def test_func(x):
+            i = 0
+            while i < x:
+                i += 1
+
+        code = test_func.__code__
+        sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START)
+        self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START)
+        test_func(1000)
+        sys.monitoring.set_local_events(TEST_TOOL, code, 0)
+        self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), 0)
index 58306075cad48b75843d916606f0f55dbf57952d..1443027ff293acac53be65ad373b18a71334ff25 100644 (file)
@@ -1479,6 +1479,23 @@ clear_executors(PyCodeObject *co)
     co->co_executors = NULL;
 }
 
+void
+_PyCode_Clear_Executors(PyCodeObject *code) {
+    int code_len = (int)Py_SIZE(code);
+    for (int i = 0; i < code_len; i += _PyInstruction_GetLength(code, i)) {
+        _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
+        uint8_t opcode = instr->op.code;
+        uint8_t oparg = instr->op.arg;
+        if (opcode == ENTER_EXECUTOR) {
+            _PyExecutorObject *exec = code->co_executors->executors[oparg];
+            assert(exec->vm_data.opcode != ENTER_EXECUTOR);
+            instr->op.code = exec->vm_data.opcode;
+            instr->op.arg = exec->vm_data.oparg;
+        }
+    }
+    clear_executors(code);
+}
+
 static void
 deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions)
 {
index 9065043f55d8a70cd07d2c6230efb13e13dd808c..acc3278d50a60a3740d579ca48aec8ceb4581b45 100644 (file)
@@ -3,6 +3,7 @@
 #include "opcode_ids.h"
 
 #include "pycore_call.h"
+#include "pycore_code.h"          // _PyCode_Clear_Executors()
 #include "pycore_frame.h"
 #include "pycore_interp.h"
 #include "pycore_long.h"
@@ -583,13 +584,7 @@ de_instrument(PyCodeObject *code, int i, int event)
     _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
     uint8_t *opcode_ptr = &instr->op.code;
     int opcode = *opcode_ptr;
-    if (opcode == ENTER_EXECUTOR) {
-        int oparg = instr->op.arg;
-        _PyExecutorObject *exec = code->co_executors->executors[oparg];
-        opcode_ptr = &exec->vm_data.opcode;
-        opcode = *opcode_ptr;
-        assert(opcode != ENTER_EXECUTOR);
-    }
+    assert(opcode != ENTER_EXECUTOR);
     if (opcode == INSTRUMENTED_LINE) {
         opcode_ptr = &code->_co_monitoring->lines[i].original_opcode;
         opcode = *opcode_ptr;
@@ -734,22 +729,7 @@ remove_tools(PyCodeObject * code, int offset, int event, int tools)
     assert(event != PY_MONITORING_EVENT_LINE);
     assert(event != PY_MONITORING_EVENT_INSTRUCTION);
     assert(PY_MONITORING_IS_INSTRUMENTED_EVENT(event));
-    #ifndef NDEBUG
-    _Py_CODEUNIT co_instr = _PyCode_CODE(code)[offset];
-    uint8_t opcode = co_instr.op.code;
-    uint8_t oparg = co_instr.op.arg;
-    if (opcode == ENTER_EXECUTOR) {
-        _PyExecutorObject *exec = code->co_executors->executors[oparg];
-        assert(exec->vm_data.opcode != ENTER_EXECUTOR);
-        opcode = _PyOpcode_Deopt[exec->vm_data.opcode];
-        opcode = exec->vm_data.oparg;
-    }
-    else {
-        opcode = _Py_GetBaseOpcode(code, offset);
-    }
-    assert(opcode != ENTER_EXECUTOR);
-    assert(opcode_has_event(opcode));
-    #endif
+    assert(opcode_has_event(_Py_GetBaseOpcode(code, offset)));
     _PyCoMonitoringData *monitoring = code->_co_monitoring;
     if (monitoring && monitoring->tools) {
         monitoring->tools[offset] &= ~tools;
@@ -1315,16 +1295,10 @@ initialize_tools(PyCodeObject *code)
     for (int i = 0; i < code_len; i++) {
         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
         int opcode = instr->op.code;
-        int oparg = instr->op.arg;
-        if (opcode == ENTER_EXECUTOR) {
-            _PyExecutorObject *exec = code->co_executors->executors[oparg];
-            opcode = exec->vm_data.opcode;
-            oparg = exec->vm_data.oparg;
-        }
-        else if (opcode == INSTRUMENTED_LINE) {
+        assert(opcode != ENTER_EXECUTOR);
+        if (opcode == INSTRUMENTED_LINE) {
             opcode = code->_co_monitoring->lines[i].original_opcode;
         }
-        assert(opcode != ENTER_EXECUTOR);
         bool instrumented = is_instrumented(opcode);
         if (instrumented) {
             opcode = DE_INSTRUMENT[opcode];
@@ -1335,7 +1309,7 @@ initialize_tools(PyCodeObject *code)
             if (instrumented) {
                 int8_t event;
                 if (opcode == RESUME) {
-                    event = oparg != 0;
+                    event = instr->op.arg != 0;
                 }
                 else {
                     event = EVENT_FOR_OPCODE[opcode];
@@ -1588,6 +1562,9 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
         );
         return 0;
     }
+    if (code->co_executors != NULL) {
+        _PyCode_Clear_Executors(code);
+    }
     int code_len = (int)Py_SIZE(code);
     /* code->_co_firsttraceable >= code_len indicates
      * that no instrumentation can be inserted.
@@ -1629,7 +1606,9 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
     for (int i = code->_co_firsttraceable; i < code_len; i+= _PyInstruction_GetLength(code, i)) {
         _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
         CHECK(instr->op.code != 0);
+        assert(instr->op.code != ENTER_EXECUTOR);
         int base_opcode = _Py_GetBaseOpcode(code, i);
+        assert(base_opcode != ENTER_EXECUTOR);
         if (opcode_has_event(base_opcode)) {
             int8_t event;
             if (base_opcode == RESUME) {