@@ -364,45 +364,21 @@ dump_instrumentation_data_per_instruction(PyCodeObject *code, _PyCoMonitoringDat
364364}
365365
366366static void
367- dump_monitors (const char * prefix , _Py_Monitors monitors , FILE * out )
367+ dump_global_monitors (const char * prefix , _Py_GlobalMonitors monitors , FILE * out )
368368{
369369 fprintf (out , "%s monitors:\n" , prefix );
370370 for (int event = 0 ; event < _PY_MONITORING_UNGROUPED_EVENTS ; event ++ ) {
371371 fprintf (out , " Event %d: Tools %x\n" , event , monitors .tools [event ]);
372372 }
373373}
374374
375- /* Like _Py_GetBaseOpcode but without asserts.
376- * Does its best to give the right answer, but won't abort
377- * if something is wrong */
378- static int
379- get_base_opcode_best_attempt (PyCodeObject * code , int offset )
375+ static void
376+ dump_local_monitors (const char * prefix , _Py_LocalMonitors monitors , FILE * out )
380377{
381- int opcode = _Py_OPCODE (_PyCode_CODE (code )[offset ]);
382- if (INSTRUMENTED_OPCODES [opcode ] != opcode ) {
383- /* Not instrumented */
384- return _PyOpcode_Deopt [opcode ] == 0 ? opcode : _PyOpcode_Deopt [opcode ];
385- }
386- if (opcode == INSTRUMENTED_INSTRUCTION ) {
387- if (code -> _co_monitoring -> per_instruction_opcodes [offset ] == 0 ) {
388- return opcode ;
389- }
390- opcode = code -> _co_monitoring -> per_instruction_opcodes [offset ];
391- }
392- if (opcode == INSTRUMENTED_LINE ) {
393- if (code -> _co_monitoring -> lines [offset ].original_opcode == 0 ) {
394- return opcode ;
395- }
396- opcode = code -> _co_monitoring -> lines [offset ].original_opcode ;
397- }
398- int deinstrumented = DE_INSTRUMENT [opcode ];
399- if (deinstrumented ) {
400- return deinstrumented ;
401- }
402- if (_PyOpcode_Deopt [opcode ] == 0 ) {
403- return opcode ;
378+ fprintf (out , "%s monitors:\n" , prefix );
379+ for (int event = 0 ; event < _PY_MONITORING_LOCAL_EVENTS ; event ++ ) {
380+ fprintf (out , " Event %d: Tools %x\n" , event , monitors .tools [event ]);
404381 }
405- return _PyOpcode_Deopt [opcode ];
406382}
407383
408384/* No error checking -- Don't use this for anything but experimental debugging */
@@ -417,9 +393,9 @@ dump_instrumentation_data(PyCodeObject *code, int star, FILE*out)
417393 fprintf (out , "NULL\n" );
418394 return ;
419395 }
420- dump_monitors ("Global" , _PyInterpreterState_GET ()-> monitors , out );
421- dump_monitors ("Code" , data -> local_monitors , out );
422- dump_monitors ("Active" , data -> active_monitors , out );
396+ dump_global_monitors ("Global" , _PyInterpreterState_GET ()-> monitors , out );
397+ dump_local_monitors ("Code" , data -> local_monitors , out );
398+ dump_local_monitors ("Active" , data -> active_monitors , out );
423399 int code_len = (int )Py_SIZE (code );
424400 bool starred = false;
425401 for (int i = 0 ; i < code_len ; i += _PyInstruction_GetLength (code , i )) {
@@ -458,6 +434,9 @@ dump_instrumentation_data(PyCodeObject *code, int star, FILE*out)
458434static bool
459435valid_opcode (int opcode )
460436{
437+ if (opcode == INSTRUMENTED_LINE ) {
438+ return true;
439+ }
461440 if (IS_VALID_OPCODE (opcode ) &&
462441 opcode != CACHE &&
463442 opcode != RESERVED &&
@@ -475,18 +454,23 @@ sanity_check_instrumentation(PyCodeObject *code)
475454 if (data == NULL ) {
476455 return ;
477456 }
478- _Py_GlobalMonitors active_monitors = _PyInterpreterState_GET ()-> monitors ;
457+ _Py_GlobalMonitors global_monitors = _PyInterpreterState_GET ()-> monitors ;
458+ _Py_LocalMonitors active_monitors ;
479459 if (code -> _co_monitoring ) {
480- _Py_Monitors local_monitors = code -> _co_monitoring -> local_monitors ;
481- active_monitors = local_union (active_monitors , local_monitors );
460+ _Py_LocalMonitors local_monitors = code -> _co_monitoring -> local_monitors ;
461+ active_monitors = local_union (global_monitors , local_monitors );
462+ }
463+ else {
464+ _Py_LocalMonitors empty = (_Py_LocalMonitors ) { 0 };
465+ active_monitors = local_union (global_monitors , empty );
482466 }
483467 assert (monitors_equals (
484468 code -> _co_monitoring -> active_monitors ,
485- active_monitors )
486- );
469+ active_monitors ));
487470 int code_len = (int )Py_SIZE (code );
488471 for (int i = 0 ; i < code_len ;) {
489- int opcode = _PyCode_CODE (code )[i ].op .code ;
472+ _Py_CODEUNIT * instr = & _PyCode_CODE (code )[i ];
473+ int opcode = instr -> op .code ;
490474 int base_opcode = _Py_GetBaseOpcode (code , i );
491475 CHECK (valid_opcode (opcode ));
492476 CHECK (valid_opcode (base_opcode ));
@@ -506,23 +490,30 @@ sanity_check_instrumentation(PyCodeObject *code)
506490 opcode = data -> lines [i ].original_opcode ;
507491 CHECK (opcode != END_FOR );
508492 CHECK (opcode != RESUME );
493+ CHECK (opcode != RESUME_CHECK );
509494 CHECK (opcode != INSTRUMENTED_RESUME );
510495 if (!is_instrumented (opcode )) {
511496 CHECK (_PyOpcode_Deopt [opcode ] == opcode );
512497 }
513498 CHECK (opcode != INSTRUMENTED_LINE );
514499 }
515- else if (data -> lines && !is_instrumented (opcode )) {
516- CHECK (data -> lines [i ].original_opcode == 0 ||
517- data -> lines [i ].original_opcode == base_opcode ||
518- DE_INSTRUMENT [data -> lines [i ].original_opcode ] == base_opcode );
500+ else if (data -> lines ) {
501+ /* If original_opcode is INSTRUMENTED_INSTRUCTION
502+ * *and* we are executing a INSTRUMENTED_LINE instruction
503+ * that has de-instrumented itself, then we will execute
504+ * an invalid INSTRUMENTED_INSTRUCTION */
505+ CHECK (data -> lines [i ].original_opcode != INSTRUMENTED_INSTRUCTION );
506+ }
507+ if (opcode == INSTRUMENTED_INSTRUCTION ) {
508+ CHECK (data -> per_instruction_opcodes [i ] != 0 );
509+ opcode = data -> per_instruction_opcodes [i ];
519510 }
520511 if (is_instrumented (opcode )) {
521512 CHECK (DE_INSTRUMENT [opcode ] == base_opcode );
522513 int event = EVENT_FOR_OPCODE [DE_INSTRUMENT [opcode ]];
523514 if (event < 0 ) {
524515 /* RESUME fixup */
525- event = _PyCode_CODE ( code )[ i ]. op .arg ;
516+ event = instr -> op .arg ? 1 : 0 ;
526517 }
527518 CHECK (active_monitors .tools [event ] != 0 );
528519 }
@@ -608,30 +599,30 @@ static void
608599de_instrument_line (PyCodeObject * code , int i )
609600{
610601 _Py_CODEUNIT * instr = & _PyCode_CODE (code )[i ];
611- uint8_t * opcode_ptr = & instr -> op .code ;
612- int opcode = * opcode_ptr ;
602+ int opcode = instr -> op .code ;
613603 if (opcode != INSTRUMENTED_LINE ) {
614604 return ;
615605 }
616606 _PyCoLineInstrumentationData * lines = & code -> _co_monitoring -> lines [i ];
617607 int original_opcode = lines -> original_opcode ;
608+ if (original_opcode == INSTRUMENTED_INSTRUCTION ) {
609+ lines -> original_opcode = code -> _co_monitoring -> per_instruction_opcodes [i ];
610+ }
618611 CHECK (original_opcode != 0 );
619612 CHECK (original_opcode == _PyOpcode_Deopt [original_opcode ]);
620- * opcode_ptr = instr -> op .code = original_opcode ;
613+ instr -> op .code = original_opcode ;
621614 if (_PyOpcode_Caches [original_opcode ]) {
622615 instr [1 ].cache = adaptive_counter_warmup ();
623616 }
624- assert (* opcode_ptr != INSTRUMENTED_LINE );
625617 assert (instr -> op .code != INSTRUMENTED_LINE );
626618}
627619
628-
629620static void
630621de_instrument_per_instruction (PyCodeObject * code , int i )
631622{
632623 _Py_CODEUNIT * instr = & _PyCode_CODE (code )[i ];
633624 uint8_t * opcode_ptr = & instr -> op .code ;
634- int opcode = * opcode_ptr ;
625+ int opcode = * opcode_ptr ;
635626 if (opcode == INSTRUMENTED_LINE ) {
636627 opcode_ptr = & code -> _co_monitoring -> lines [i ].original_opcode ;
637628 opcode = * opcode_ptr ;
@@ -642,10 +633,11 @@ de_instrument_per_instruction(PyCodeObject *code, int i)
642633 int original_opcode = code -> _co_monitoring -> per_instruction_opcodes [i ];
643634 CHECK (original_opcode != 0 );
644635 CHECK (original_opcode == _PyOpcode_Deopt [original_opcode ]);
645- instr -> op . code = original_opcode ;
636+ * opcode_ptr = original_opcode ;
646637 if (_PyOpcode_Caches [original_opcode ]) {
647638 instr [1 ].cache = adaptive_counter_warmup ();
648639 }
640+ assert (* opcode_ptr != INSTRUMENTED_INSTRUCTION );
649641 assert (instr -> op .code != INSTRUMENTED_INSTRUCTION );
650642 /* Keep things clean for sanity check */
651643 code -> _co_monitoring -> per_instruction_opcodes [i ] = 0 ;
@@ -685,7 +677,7 @@ static void
685677instrument_line (PyCodeObject * code , int i )
686678{
687679 uint8_t * opcode_ptr = & _PyCode_CODE (code )[i ].op .code ;
688- int opcode = * opcode_ptr ;
680+ int opcode = * opcode_ptr ;
689681 if (opcode == INSTRUMENTED_LINE ) {
690682 return ;
691683 }
@@ -700,13 +692,14 @@ instrument_per_instruction(PyCodeObject *code, int i)
700692{
701693 _Py_CODEUNIT * instr = & _PyCode_CODE (code )[i ];
702694 uint8_t * opcode_ptr = & instr -> op .code ;
703- int opcode = * opcode_ptr ;
695+ int opcode = * opcode_ptr ;
704696 if (opcode == INSTRUMENTED_LINE ) {
705697 _PyCoLineInstrumentationData * lines = & code -> _co_monitoring -> lines [i ];
706698 opcode_ptr = & lines -> original_opcode ;
707699 opcode = * opcode_ptr ;
708700 }
709701 if (opcode == INSTRUMENTED_INSTRUCTION ) {
702+ assert (code -> _co_monitoring -> per_instruction_opcodes [i ] > 0 );
710703 return ;
711704 }
712705 CHECK (opcode != 0 );
@@ -1129,7 +1122,6 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
11291122
11301123 _PyCoMonitoringData * monitoring = code -> _co_monitoring ;
11311124 _PyCoLineInstrumentationData * line_data = & monitoring -> lines [i ];
1132- uint8_t original_opcode = line_data -> original_opcode ;
11331125 if (tstate -> tracing ) {
11341126 goto done ;
11351127 }
@@ -1212,7 +1204,9 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
12121204 }
12131205 } while (tools );
12141206 Py_DECREF (line_obj );
1207+ uint8_t original_opcode ;
12151208done :
1209+ original_opcode = line_data -> original_opcode ;
12161210 assert (original_opcode != 0 );
12171211 assert (original_opcode != INSTRUMENTED_LINE );
12181212 assert (_PyOpcode_Deopt [original_opcode ] == original_opcode );
@@ -1655,7 +1649,9 @@ _Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
16551649 i += _PyInstruction_GetLength (code , i );
16561650 }
16571651 }
1658-
1652+ #ifdef INSTRUMENT_DEBUG
1653+ sanity_check_instrumentation (code );
1654+ #endif
16591655 uint8_t new_line_tools = new_events .tools [PY_MONITORING_EVENT_LINE ];
16601656 uint8_t new_per_instruction_tools = new_events .tools [PY_MONITORING_EVENT_INSTRUCTION ];
16611657
0 commit comments