@@ -459,7 +459,6 @@ dump_instrumentation_data(PyCodeObject *code, int star, FILE*out)
459
459
}
460
460
461
461
#define CHECK (test ) do { \
462
- ASSERT_WORLD_STOPPED_OR_LOCKED(code); \
463
462
if (!(test)) { \
464
463
dump_instrumentation_data(code, i, stderr); \
465
464
} \
@@ -516,10 +515,6 @@ sanity_check_instrumentation(PyCodeObject *code)
516
515
if (!is_instrumented (opcode )) {
517
516
CHECK (_PyOpcode_Deopt [opcode ] == opcode );
518
517
}
519
- if (data -> per_instruction_tools ) {
520
- uint8_t tools = active_monitors .tools [PY_MONITORING_EVENT_INSTRUCTION ];
521
- CHECK ((tools & data -> per_instruction_tools [i ]) == data -> per_instruction_tools [i ]);
522
- }
523
518
}
524
519
if (opcode == INSTRUMENTED_LINE ) {
525
520
CHECK (data -> lines );
@@ -677,8 +672,6 @@ de_instrument_per_instruction(PyCodeObject *code, int i)
677
672
}
678
673
assert (* opcode_ptr != INSTRUMENTED_INSTRUCTION );
679
674
assert (instr -> op .code != INSTRUMENTED_INSTRUCTION );
680
- /* Keep things clean for sanity check */
681
- code -> _co_monitoring -> per_instruction_opcodes [i ] = 0 ;
682
675
}
683
676
684
677
@@ -992,18 +985,32 @@ set_global_version(PyThreadState *tstate, uint32_t version)
992
985
static bool
993
986
is_version_up_to_date (PyCodeObject * code , PyInterpreterState * interp )
994
987
{
988
+ ASSERT_WORLD_STOPPED_OR_LOCKED (code );
995
989
return global_version (interp ) == code -> _co_instrumentation_version ;
996
990
}
997
991
998
992
#ifndef NDEBUG
999
993
static bool
1000
994
instrumentation_cross_checks (PyInterpreterState * interp , PyCodeObject * code )
1001
995
{
996
+ ASSERT_WORLD_STOPPED_OR_LOCKED (code );
1002
997
_Py_LocalMonitors expected = local_union (
1003
998
interp -> monitors ,
1004
999
code -> _co_monitoring -> local_monitors );
1005
1000
return monitors_equals (code -> _co_monitoring -> active_monitors , expected );
1006
1001
}
1002
+
1003
+ static inline
1004
+ int debug_check_sanity (PyInterpreterState * interp , PyCodeObject * code )
1005
+ {
1006
+ int res ;
1007
+ LOCK_CODE (code );
1008
+ res = is_version_up_to_date (code , interp ) &&
1009
+ instrumentation_cross_checks (interp , code );
1010
+ UNLOCK_CODE ();
1011
+ return res ;
1012
+ }
1013
+
1007
1014
#endif
1008
1015
1009
1016
static inline uint8_t
@@ -1018,8 +1025,7 @@ get_tools_for_instruction(PyCodeObject *code, PyInterpreterState *interp, int i,
1018
1025
event = PY_MONITORING_EVENT_CALL ;
1019
1026
}
1020
1027
if (PY_MONITORING_IS_INSTRUMENTED_EVENT (event )) {
1021
- CHECK (is_version_up_to_date (code , interp ));
1022
- CHECK (instrumentation_cross_checks (interp , code ));
1028
+ CHECK (debug_check_sanity (interp , code ));
1023
1029
if (code -> _co_monitoring -> tools ) {
1024
1030
tools = code -> _co_monitoring -> tools [i ];
1025
1031
}
@@ -1217,8 +1223,7 @@ int
1217
1223
_Py_call_instrumentation_line (PyThreadState * tstate , _PyInterpreterFrame * frame , _Py_CODEUNIT * instr , _Py_CODEUNIT * prev )
1218
1224
{
1219
1225
PyCodeObject * code = _PyFrame_GetCode (frame );
1220
- assert (is_version_up_to_date (code , tstate -> interp ));
1221
- assert (instrumentation_cross_checks (tstate -> interp , code ));
1226
+ assert (debug_check_sanity (tstate -> interp , code ));
1222
1227
int i = (int )(instr - _PyCode_CODE (code ));
1223
1228
1224
1229
_PyCoMonitoringData * monitoring = code -> _co_monitoring ;
@@ -1341,8 +1346,7 @@ int
1341
1346
_Py_call_instrumentation_instruction (PyThreadState * tstate , _PyInterpreterFrame * frame , _Py_CODEUNIT * instr )
1342
1347
{
1343
1348
PyCodeObject * code = _PyFrame_GetCode (frame );
1344
- assert (is_version_up_to_date (code , tstate -> interp ));
1345
- assert (instrumentation_cross_checks (tstate -> interp , code ));
1349
+ assert (debug_check_sanity (tstate -> interp , code ));
1346
1350
int offset = (int )(instr - _PyCode_CODE (code ));
1347
1351
_PyCoMonitoringData * instrumentation_data = code -> _co_monitoring ;
1348
1352
assert (instrumentation_data -> per_instruction_opcodes );
@@ -1673,9 +1677,11 @@ update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp)
1673
1677
PyErr_NoMemory ();
1674
1678
return -1 ;
1675
1679
}
1676
- /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */
1680
+ // Initialize all of the instructions so if local events change while another thread is executing
1681
+ // we know what the original opcode was.
1677
1682
for (int i = 0 ; i < code_len ; i ++ ) {
1678
- code -> _co_monitoring -> per_instruction_opcodes [i ] = 0 ;
1683
+ int opcode = _PyCode_CODE (code )[i ].op .code ;
1684
+ code -> _co_monitoring -> per_instruction_opcodes [i ] = _PyOpcode_Deopt [opcode ];
1679
1685
}
1680
1686
}
1681
1687
if (multitools && code -> _co_monitoring -> per_instruction_tools == NULL ) {
@@ -1684,27 +1690,22 @@ update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp)
1684
1690
PyErr_NoMemory ();
1685
1691
return -1 ;
1686
1692
}
1687
- /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */
1693
+ // Initialize all of the instructions so if local events change while another thread is executing
1694
+ // we know what the original opcode was.
1688
1695
for (int i = 0 ; i < code_len ; i ++ ) {
1689
- code -> _co_monitoring -> per_instruction_tools [i ] = 0 ;
1696
+ int opcode = _PyCode_CODE (code )[i ].op .code ;
1697
+ code -> _co_monitoring -> per_instruction_tools [i ] = _PyOpcode_Deopt [opcode ];
1690
1698
}
1691
1699
}
1692
1700
}
1693
1701
return 0 ;
1694
1702
}
1695
1703
1696
1704
static int
1697
- instrument_lock_held (PyCodeObject * code , PyInterpreterState * interp )
1705
+ force_instrument_lock_held (PyCodeObject * code , PyInterpreterState * interp )
1698
1706
{
1699
1707
ASSERT_WORLD_STOPPED_OR_LOCKED (code );
1700
1708
1701
- if (is_version_up_to_date (code , interp )) {
1702
- assert (
1703
- interp -> ceval .instrumentation_version == 0 ||
1704
- instrumentation_cross_checks (interp , code )
1705
- );
1706
- return 0 ;
1707
- }
1708
1709
#ifdef _Py_TIER2
1709
1710
if (code -> co_executors != NULL ) {
1710
1711
_PyCode_Clear_Executors (code );
@@ -1771,17 +1772,14 @@ instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp)
1771
1772
1772
1773
// GH-103845: We need to remove both the line and instruction instrumentation before
1773
1774
// adding new ones, otherwise we may remove the newly added instrumentation.
1774
-
1775
1775
uint8_t removed_line_tools = removed_events .tools [PY_MONITORING_EVENT_LINE ];
1776
1776
uint8_t removed_per_instruction_tools = removed_events .tools [PY_MONITORING_EVENT_INSTRUCTION ];
1777
1777
1778
1778
if (removed_line_tools ) {
1779
1779
_PyCoLineInstrumentationData * line_data = code -> _co_monitoring -> lines ;
1780
1780
for (int i = code -> _co_firsttraceable ; i < code_len ;) {
1781
1781
if (line_data [i ].original_opcode ) {
1782
- if (removed_line_tools ) {
1783
- remove_line_tools (code , i , removed_line_tools );
1784
- }
1782
+ remove_line_tools (code , i , removed_line_tools );
1785
1783
}
1786
1784
i += _PyInstruction_GetLength (code , i );
1787
1785
}
@@ -1793,25 +1791,22 @@ instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp)
1793
1791
i += _PyInstruction_GetLength (code , i );
1794
1792
continue ;
1795
1793
}
1796
- if (removed_per_instruction_tools ) {
1797
- remove_per_instruction_tools (code , i , removed_per_instruction_tools );
1798
- }
1794
+ remove_per_instruction_tools (code , i , removed_per_instruction_tools );
1799
1795
i += _PyInstruction_GetLength (code , i );
1800
1796
}
1801
1797
}
1802
1798
#ifdef INSTRUMENT_DEBUG
1803
1799
sanity_check_instrumentation (code );
1804
1800
#endif
1801
+
1805
1802
uint8_t new_line_tools = new_events .tools [PY_MONITORING_EVENT_LINE ];
1806
1803
uint8_t new_per_instruction_tools = new_events .tools [PY_MONITORING_EVENT_INSTRUCTION ];
1807
1804
1808
1805
if (new_line_tools ) {
1809
1806
_PyCoLineInstrumentationData * line_data = code -> _co_monitoring -> lines ;
1810
1807
for (int i = code -> _co_firsttraceable ; i < code_len ;) {
1811
1808
if (line_data [i ].original_opcode ) {
1812
- if (new_line_tools ) {
1813
- add_line_tools (code , i , new_line_tools );
1814
- }
1809
+ add_line_tools (code , i , new_line_tools );
1815
1810
}
1816
1811
i += _PyInstruction_GetLength (code , i );
1817
1812
}
@@ -1823,12 +1818,11 @@ instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp)
1823
1818
i += _PyInstruction_GetLength (code , i );
1824
1819
continue ;
1825
1820
}
1826
- if (new_per_instruction_tools ) {
1827
- add_per_instruction_tools (code , i , new_per_instruction_tools );
1828
- }
1821
+ add_per_instruction_tools (code , i , new_per_instruction_tools );
1829
1822
i += _PyInstruction_GetLength (code , i );
1830
1823
}
1831
1824
}
1825
+
1832
1826
done :
1833
1827
FT_ATOMIC_STORE_UINTPTR_RELEASE (code -> _co_instrumentation_version ,
1834
1828
global_version (interp ));
@@ -1839,6 +1833,22 @@ instrument_lock_held(PyCodeObject *code, PyInterpreterState *interp)
1839
1833
return 0 ;
1840
1834
}
1841
1835
1836
+ static int
1837
+ instrument_lock_held (PyCodeObject * code , PyInterpreterState * interp )
1838
+ {
1839
+ ASSERT_WORLD_STOPPED_OR_LOCKED (code );
1840
+
1841
+ if (is_version_up_to_date (code , interp )) {
1842
+ assert (
1843
+ interp -> ceval .instrumentation_version == 0 ||
1844
+ instrumentation_cross_checks (interp , code )
1845
+ );
1846
+ return 0 ;
1847
+ }
1848
+
1849
+ return force_instrument_lock_held (code , interp );
1850
+ }
1851
+
1842
1852
int
1843
1853
_Py_Instrument (PyCodeObject * code , PyInterpreterState * interp )
1844
1854
{
@@ -1985,16 +1995,8 @@ _PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEvent
1985
1995
goto done ;
1986
1996
}
1987
1997
set_local_events (local , tool_id , events );
1988
- if (is_version_up_to_date (code , interp )) {
1989
- /* Force instrumentation update */
1990
- code -> _co_instrumentation_version -= MONITORING_VERSION_INCREMENT ;
1991
- }
1992
-
1993
- #ifdef _Py_TIER2
1994
- _Py_Executors_InvalidateDependency (interp , code , 1 );
1995
- #endif
1996
1998
1997
- res = instrument_lock_held (code , interp );
1999
+ res = force_instrument_lock_held (code , interp );
1998
2000
1999
2001
done :
2000
2002
UNLOCK_CODE ();
0 commit comments