@@ -268,14 +268,15 @@ get_events(_Py_GlobalMonitors *m, int tool_id)
268268 * 8 bit value.
269269 * if line_delta == -128:
270270 * line = None # represented as -1
271- * elif line_delta == -127:
271+ * elif line_delta == -127 or line_delta == -126 :
272272 * line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT));
273273 * else:
274274 * line = first_line + (offset >> OFFSET_SHIFT) + line_delta;
275275 */
276276
277277#define NO_LINE -128
278- #define COMPUTED_LINE -127
278+ #define COMPUTED_LINE_LINENO_CHANGE -127
279+ #define COMPUTED_LINE -126
279280
280281#define OFFSET_SHIFT 4
281282
@@ -302,7 +303,7 @@ compute_line(PyCodeObject *code, int offset, int8_t line_delta)
302303
303304 return -1 ;
304305 }
305- assert (line_delta == COMPUTED_LINE );
306+ assert (line_delta == COMPUTED_LINE || line_delta == COMPUTED_LINE_LINENO_CHANGE );
306307 /* Look it up */
307308 return PyCode_Addr2Line (code , offset * sizeof (_Py_CODEUNIT ));
308309}
@@ -1224,18 +1225,26 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
12241225 }
12251226 PyInterpreterState * interp = tstate -> interp ;
12261227 int8_t line_delta = line_data -> line_delta ;
1227- int line = compute_line (code , i , line_delta );
1228- assert (line >= 0 );
1229- assert (prev != NULL );
1230- int prev_index = (int )(prev - _PyCode_CODE (code ));
1231- int prev_line = _Py_Instrumentation_GetLine (code , prev_index );
1232- if (prev_line == line ) {
1233- int prev_opcode = _PyCode_CODE (code )[prev_index ].op .code ;
1234- /* RESUME and INSTRUMENTED_RESUME are needed for the operation of
1235- * instrumentation, so must never be hidden by an INSTRUMENTED_LINE.
1236- */
1237- if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME ) {
1238- goto done ;
1228+ int line = 0 ;
1229+
1230+ if (line_delta == COMPUTED_LINE_LINENO_CHANGE ) {
1231+ // We know the line number must have changed, don't need to calculate
1232+ // the line number for now because we might not need it.
1233+ line = -1 ;
1234+ } else {
1235+ line = compute_line (code , i , line_delta );
1236+ assert (line >= 0 );
1237+ assert (prev != NULL );
1238+ int prev_index = (int )(prev - _PyCode_CODE (code ));
1239+ int prev_line = _Py_Instrumentation_GetLine (code , prev_index );
1240+ if (prev_line == line ) {
1241+ int prev_opcode = _PyCode_CODE (code )[prev_index ].op .code ;
1242+ /* RESUME and INSTRUMENTED_RESUME are needed for the operation of
1243+ * instrumentation, so must never be hidden by an INSTRUMENTED_LINE.
1244+ */
1245+ if (prev_opcode != RESUME && prev_opcode != INSTRUMENTED_RESUME ) {
1246+ goto done ;
1247+ }
12391248 }
12401249 }
12411250
@@ -1260,6 +1269,12 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
12601269 tstate -> tracing ++ ;
12611270 /* Call c_tracefunc directly, having set the line number. */
12621271 Py_INCREF (frame_obj );
1272+ if (line == -1 && line_delta > COMPUTED_LINE ) {
1273+ /* Only assign f_lineno if it's easy to calculate, otherwise
1274+ * do lazy calculation by setting the f_lineno to 0.
1275+ */
1276+ line = compute_line (code , i , line_delta );
1277+ }
12631278 frame_obj -> f_lineno = line ;
12641279 int err = tstate -> c_tracefunc (tstate -> c_traceobj , frame_obj , PyTrace_LINE , Py_None );
12651280 frame_obj -> f_lineno = 0 ;
@@ -1276,6 +1291,11 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
12761291 if (tools == 0 ) {
12771292 goto done ;
12781293 }
1294+
1295+ if (line == -1 ) {
1296+ /* Need to calculate the line number now for monitoring events */
1297+ line = compute_line (code , i , line_delta );
1298+ }
12791299 PyObject * line_obj = PyLong_FromLong (line );
12801300 if (line_obj == NULL ) {
12811301 return -1 ;
@@ -1477,6 +1497,13 @@ initialize_lines(PyCodeObject *code)
14771497 */
14781498 if (line != current_line && line >= 0 ) {
14791499 line_data [i ].original_opcode = opcode ;
1500+ if (line_data [i ].line_delta == COMPUTED_LINE ) {
1501+ /* Label this line as a line with a line number change
1502+ * which could help the monitoring callback to quickly
1503+ * identify the line number change.
1504+ */
1505+ line_data [i ].line_delta = COMPUTED_LINE_LINENO_CHANGE ;
1506+ }
14801507 }
14811508 else {
14821509 line_data [i ].original_opcode = 0 ;
@@ -1529,6 +1556,11 @@ initialize_lines(PyCodeObject *code)
15291556 assert (target >= 0 );
15301557 if (line_data [target ].line_delta != NO_LINE ) {
15311558 line_data [target ].original_opcode = _Py_GetBaseOpcode (code , target );
1559+ if (line_data [target ].line_delta == COMPUTED_LINE_LINENO_CHANGE ) {
1560+ // If the line is a jump target, we are not sure if the line
1561+ // number changes, so we set it to COMPUTED_LINE.
1562+ line_data [target ].line_delta = COMPUTED_LINE ;
1563+ }
15321564 }
15331565 }
15341566 /* Scan exception table */
0 commit comments