Skip to content

Commit c41a1f9

Browse files
committed
pythonGH-127953: Make line number lookup O(1) regardless of the size of the code object (pythonGH-128350)
1 parent e8dbe7e commit c41a1f9

File tree

5 files changed

+208
-156
lines changed

5 files changed

+208
-156
lines changed

Include/cpython/code.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,12 @@ typedef struct {
3333
} _PyCoCached;
3434

3535
/* Ancillary data structure used for instrumentation.
36-
Line instrumentation creates an array of
37-
these. One entry per code unit.*/
36+
Line instrumentation creates this with sufficient
37+
space for one entry per code unit. The total size
38+
of the data will be `bytes_per_entry * Py_SIZE(code)` */
3839
typedef struct {
39-
uint8_t original_opcode;
40-
int8_t line_delta;
40+
uint8_t bytes_per_entry;
41+
uint8_t data[1];
4142
} _PyCoLineInstrumentationData;
4243

4344

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The time to handle a ``LINE`` event in sys.monitoring (and sys.settrace) is
2+
now independent of the number of lines in the code object.

Objects/codeobject.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -944,6 +944,9 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq)
944944
if (addrq < 0) {
945945
return co->co_firstlineno;
946946
}
947+
if (co->_co_monitoring && co->_co_monitoring->lines) {
948+
return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT));
949+
}
947950
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
948951
PyCodeAddressRange bounds;
949952
_PyCode_InitAddressRange(co, &bounds);

Python/ceval.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -801,8 +801,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
801801
int original_opcode = 0;
802802
if (tstate->tracing) {
803803
PyCodeObject *code = _PyFrame_GetCode(frame);
804-
original_opcode = code->_co_monitoring->lines[(int)(here - _PyCode_CODE(code))].original_opcode;
805-
} else {
804+
int index = (int)(here - _PyCode_CODE(code));
805+
original_opcode = code->_co_monitoring->lines->data[index*code->_co_monitoring->lines->bytes_per_entry];
806+
}
807+
else {
806808
_PyFrame_SetStackPointer(frame, stack_pointer);
807809
original_opcode = _Py_call_instrumentation_line(
808810
tstate, frame, here, prev);

0 commit comments

Comments
 (0)