Skip to content

Commit 262abf1

Browse files
committed
Use co_monitoring line info in PyCode_Addr2Line if it is available
1 parent 751143f commit 262abf1

File tree

2 files changed

+45
-32
lines changed

2 files changed

+45
-32
lines changed

Objects/codeobject.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,9 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq)
977977
if (addrq < 0) {
978978
return co->co_firstlineno;
979979
}
980+
if (co->_co_monitoring && co->_co_monitoring->lines) {
981+
return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT));
982+
}
980983
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
981984
PyCodeAddressRange bounds;
982985
_PyCode_InitAddressRange(co, &bounds);

Python/instrumentation.c

Lines changed: 42 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,12 @@ dump_local_monitors(const char *prefix, _Py_LocalMonitors monitors, FILE*out)
462462
}
463463
}
464464

465+
/** NOTE:
466+
* Do not use PyCode_Addr2Line to determine the line number in instrumentation,
467+
* as `PyCode_Addr2Line` uses the monitoring data if it is available.
468+
*/
469+
470+
465471
/* No error checking -- Don't use this for anything but experimental debugging */
466472
static void
467473
dump_instrumentation_data(PyCodeObject *code, int star, FILE*out)
@@ -479,14 +485,16 @@ dump_instrumentation_data(PyCodeObject *code, int star, FILE*out)
479485
dump_local_monitors("Active", data->active_monitors, out);
480486
int code_len = (int)Py_SIZE(code);
481487
bool starred = false;
488+
PyCodeAddressRange range;
489+
_PyCode_InitAddressRange(code, &range);
482490
for (int i = 0; i < code_len; i += _PyInstruction_GetLength(code, i)) {
483491
_Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
484492
int opcode = instr->op.code;
485493
if (i == star) {
486494
fprintf(out, "** ");
487495
starred = true;
488496
}
489-
fprintf(out, "Offset: %d, line: %d %s: ", i, PyCode_Addr2Line(code, i*2), _PyOpcode_OpName[opcode]);
497+
fprintf(out, "Offset: %d, line: %d %s: ", i, _PyCode_CheckLineNumber(i*2, &range), _PyOpcode_OpName[opcode]);
490498
dump_instrumentation_data_tools(code, data->tools, i, out);
491499
dump_instrumentation_data_lines(code, data->lines, i, out);
492500
dump_instrumentation_data_line_tools(code, data->line_tools, i, out);
@@ -551,6 +559,8 @@ sanity_check_instrumentation(PyCodeObject *code)
551559
code->_co_monitoring->active_monitors,
552560
active_monitors));
553561
int code_len = (int)Py_SIZE(code);
562+
PyCodeAddressRange range;
563+
_PyCode_InitAddressRange(co, &range);
554564
for (int i = 0; i < code_len;) {
555565
_Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
556566
int opcode = instr->op.code;
@@ -598,7 +608,7 @@ sanity_check_instrumentation(PyCodeObject *code)
598608
}
599609
if (data->lines && get_original_opcode(data->lines, i)) {
600610
int line1 = compute_line(code, get_line_delta(data->lines, i));
601-
int line2 = PyCode_Addr2Line(code, i*sizeof(_Py_CODEUNIT));
611+
int line2 = _PyCode_CheckLineNumber(i*sizeof(_Py_CODEUNIT), &range);
602612
CHECK(line1 == line2);
603613
}
604614
CHECK(valid_opcode(opcode));
@@ -1284,7 +1294,6 @@ _Py_Instrumentation_GetLine(PyCodeObject *code, int index)
12841294
_PyCoMonitoringData *monitoring = code->_co_monitoring;
12851295
assert(monitoring != NULL);
12861296
assert(monitoring->lines != NULL);
1287-
assert(index >= code->_co_firsttraceable);
12881297
assert(index < Py_SIZE(code));
12891298
_PyCoLineInstrumentationData *line_data = monitoring->lines;
12901299
int line_delta = get_line_delta(line_data, index);
@@ -1513,41 +1522,42 @@ initialize_lines(PyCodeObject *code, int bytes_per_entry)
15131522
int code_len = (int)Py_SIZE(code);
15141523
PyCodeAddressRange range;
15151524
_PyCode_InitAddressRange(code, &range);
1516-
for (int i = 0; i < code->_co_firsttraceable && i < code_len; i++) {
1517-
set_original_opcode(line_data, i, 0);
1518-
set_line_delta(line_data, i, NO_LINE);
1519-
}
15201525
int current_line = -1;
1521-
for (int i = code->_co_firsttraceable; i < code_len; ) {
1526+
for (int i = 0; i < code_len; ) {
15221527
int opcode = _Py_GetBaseCodeUnit(code, i).op.code;
15231528
int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range);
15241529
set_line_delta(line_data, i, compute_line_delta(code, line));
15251530
int length = _PyInstruction_GetLength(code, i);
1526-
switch (opcode) {
1527-
case END_ASYNC_FOR:
1528-
case END_FOR:
1529-
case END_SEND:
1530-
case RESUME:
1531-
/* END_FOR cannot start a line, as it is skipped by FOR_ITER
1532-
* END_SEND cannot start a line, as it is skipped by SEND
1533-
* RESUME must not be instrumented with INSTRUMENT_LINE */
1534-
set_original_opcode(line_data, i, 0);
1535-
break;
1536-
default:
1537-
/* Set original_opcode to the opcode iff the instruction
1538-
* starts a line, and thus should be instrumented.
1539-
* This saves having to perform this check every time the
1540-
* we turn instrumentation on or off, and serves as a sanity
1541-
* check when debugging.
1542-
*/
1543-
if (line != current_line && line >= 0) {
1544-
set_original_opcode(line_data, i, opcode);
1545-
CHECK(get_line_delta(line_data, i) != NO_LINE);
1546-
}
1547-
else {
1531+
if (i < code->_co_firsttraceable) {
1532+
set_original_opcode(line_data, i, 0);
1533+
}
1534+
else {
1535+
switch (opcode) {
1536+
case END_ASYNC_FOR:
1537+
case END_FOR:
1538+
case END_SEND:
1539+
case RESUME:
1540+
/* END_FOR cannot start a line, as it is skipped by FOR_ITER
1541+
* END_SEND cannot start a line, as it is skipped by SEND
1542+
* RESUME must not be instrumented with INSTRUMENT_LINE */
15481543
set_original_opcode(line_data, i, 0);
1549-
}
1550-
current_line = line;
1544+
break;
1545+
default:
1546+
/* Set original_opcode to the opcode iff the instruction
1547+
* starts a line, and thus should be instrumented.
1548+
* This saves having to perform this check every time the
1549+
* we turn instrumentation on or off, and serves as a sanity
1550+
* check when debugging.
1551+
*/
1552+
if (line != current_line && line >= 0) {
1553+
set_original_opcode(line_data, i, opcode);
1554+
CHECK(get_line_delta(line_data, i) != NO_LINE);
1555+
}
1556+
else {
1557+
set_original_opcode(line_data, i, 0);
1558+
}
1559+
current_line = line;
1560+
}
15511561
}
15521562
for (int j = 1; j < length; j++) {
15531563
set_original_opcode(line_data, i+j, 0);

0 commit comments

Comments
 (0)