@@ -268,14 +268,15 @@ get_events(_Py_GlobalMonitors *m, int tool_id)
268
268
* 8 bit value.
269
269
* if line_delta == -128:
270
270
* line = None # represented as -1
271
- * elif line_delta == -127:
271
+ * elif line_delta == -127 or line_delta == -126 :
272
272
* line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT));
273
273
* else:
274
274
* line = first_line + (offset >> OFFSET_SHIFT) + line_delta;
275
275
*/
276
276
277
277
#define NO_LINE -128
278
- #define COMPUTED_LINE -127
278
+ #define COMPUTED_LINE_LINENO_CHANGE -127
279
+ #define COMPUTED_LINE -126
279
280
280
281
#define OFFSET_SHIFT 4
281
282
@@ -302,7 +303,7 @@ compute_line(PyCodeObject *code, int offset, int8_t line_delta)
302
303
303
304
return -1 ;
304
305
}
305
- assert (line_delta == COMPUTED_LINE );
306
+ assert (line_delta == COMPUTED_LINE || line_delta == COMPUTED_LINE_LINENO_CHANGE );
306
307
/* Look it up */
307
308
return PyCode_Addr2Line (code , offset * sizeof (_Py_CODEUNIT ));
308
309
}
@@ -1224,18 +1225,26 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
1224
1225
}
1225
1226
PyInterpreterState * interp = tstate -> interp ;
1226
1227
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
+ }
1239
1248
}
1240
1249
}
1241
1250
@@ -1260,6 +1269,12 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
1260
1269
tstate -> tracing ++ ;
1261
1270
/* Call c_tracefunc directly, having set the line number. */
1262
1271
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
+ }
1263
1278
frame_obj -> f_lineno = line ;
1264
1279
int err = tstate -> c_tracefunc (tstate -> c_traceobj , frame_obj , PyTrace_LINE , Py_None );
1265
1280
frame_obj -> f_lineno = 0 ;
@@ -1276,6 +1291,11 @@ _Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
1276
1291
if (tools == 0 ) {
1277
1292
goto done ;
1278
1293
}
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
+ }
1279
1299
PyObject * line_obj = PyLong_FromLong (line );
1280
1300
if (line_obj == NULL ) {
1281
1301
return -1 ;
@@ -1477,6 +1497,13 @@ initialize_lines(PyCodeObject *code)
1477
1497
*/
1478
1498
if (line != current_line && line >= 0 ) {
1479
1499
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
+ }
1480
1507
}
1481
1508
else {
1482
1509
line_data [i ].original_opcode = 0 ;
@@ -1529,6 +1556,11 @@ initialize_lines(PyCodeObject *code)
1529
1556
assert (target >= 0 );
1530
1557
if (line_data [target ].line_delta != NO_LINE ) {
1531
1558
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
+ }
1532
1564
}
1533
1565
}
1534
1566
/* Scan exception table */
0 commit comments