Skip to content

Commit 3f38632

Browse files
authored
[3.13] GH-127953: Make line number lookup O(1) regardless of the size of the code object (#129127)
GH-127953: Make line number lookup O(1) regardless of the size of the code object (GH-128350)
1 parent 1fcf409 commit 3f38632

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
@@ -987,6 +987,9 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq)
987987
if (addrq < 0) {
988988
return co->co_firstlineno;
989989
}
990+
if (co->_co_monitoring && co->_co_monitoring->lines) {
991+
return _Py_Instrumentation_GetLine(co, addrq/sizeof(_Py_CODEUNIT));
992+
}
990993
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
991994
PyCodeAddressRange bounds;
992995
_PyCode_InitAddressRange(co, &bounds);

Python/ceval.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -804,8 +804,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
804804
int original_opcode = 0;
805805
if (tstate->tracing) {
806806
PyCodeObject *code = _PyFrame_GetCode(frame);
807-
original_opcode = code->_co_monitoring->lines[(int)(here - _PyCode_CODE(code))].original_opcode;
808-
} else {
807+
int index = (int)(here - _PyCode_CODE(code));
808+
original_opcode = code->_co_monitoring->lines->data[index*code->_co_monitoring->lines->bytes_per_entry];
809+
}
810+
else {
809811
_PyFrame_SetStackPointer(frame, stack_pointer);
810812
original_opcode = _Py_call_instrumentation_line(
811813
tstate, frame, here, prev);

0 commit comments

Comments
 (0)