aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Objects/codeobject.c
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-04-18 12:39:32 +0300
committershadchin <shadchin@yandex-team.ru>2022-04-18 12:39:32 +0300
commitd4be68e361f4258cf0848fc70018dfe37a2acc24 (patch)
tree153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Objects/codeobject.c
parent260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff)
downloadydb-d4be68e361f4258cf0848fc70018dfe37a2acc24.tar.gz
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Objects/codeobject.c')
-rw-r--r--contrib/tools/python3/src/Objects/codeobject.c485
1 files changed, 360 insertions, 125 deletions
diff --git a/contrib/tools/python3/src/Objects/codeobject.c b/contrib/tools/python3/src/Objects/codeobject.c
index cb4fb681243..c9f922707e9 100644
--- a/contrib/tools/python3/src/Objects/codeobject.c
+++ b/contrib/tools/python3/src/Objects/codeobject.c
@@ -4,10 +4,10 @@
#include "code.h"
#include "opcode.h"
#include "structmember.h" // PyMemberDef
-#include "pycore_code.h"
+#include "pycore_code.h" // _PyOpcache
#include "pycore_interp.h" // PyInterpreterState.co_extra_freefuncs
#include "pycore_pystate.h" // _PyInterpreterState_GET()
-#include "pycore_tupleobject.h"
+#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "clinic/codeobject.c.h"
/* Holder for co_extra information */
@@ -119,7 +119,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
PyObject *code, PyObject *consts, PyObject *names,
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
PyObject *filename, PyObject *name, int firstlineno,
- PyObject *lnotab)
+ PyObject *linetable)
{
PyCodeObject *co;
Py_ssize_t *cell2arg = NULL;
@@ -137,7 +137,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
cellvars == NULL || !PyTuple_Check(cellvars) ||
name == NULL || !PyUnicode_Check(name) ||
filename == NULL || !PyUnicode_Check(filename) ||
- lnotab == NULL || !PyBytes_Check(lnotab)) {
+ linetable == NULL || !PyBytes_Check(linetable)) {
PyErr_BadInternalCall();
return NULL;
}
@@ -213,7 +213,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
PyObject *arg = PyTuple_GET_ITEM(varnames, j);
int cmp = PyUnicode_Compare(cell, arg);
if (cmp == -1 && PyErr_Occurred()) {
- PyMem_FREE(cell2arg);
+ PyMem_Free(cell2arg);
return NULL;
}
if (cmp == 0) {
@@ -224,14 +224,14 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
}
}
if (!used_cell2arg) {
- PyMem_FREE(cell2arg);
+ PyMem_Free(cell2arg);
cell2arg = NULL;
}
}
co = PyObject_New(PyCodeObject, &PyCode_Type);
if (co == NULL) {
if (cell2arg)
- PyMem_FREE(cell2arg);
+ PyMem_Free(cell2arg);
return NULL;
}
co->co_argcount = argcount;
@@ -258,8 +258,8 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
Py_INCREF(name);
co->co_name = name;
co->co_firstlineno = firstlineno;
- Py_INCREF(lnotab);
- co->co_lnotab = lnotab;
+ Py_INCREF(linetable);
+ co->co_linetable = linetable;
co->co_zombieframe = NULL;
co->co_weakreflist = NULL;
co->co_extra = NULL;
@@ -277,12 +277,12 @@ PyCode_New(int argcount, int kwonlyargcount,
PyObject *code, PyObject *consts, PyObject *names,
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
PyObject *filename, PyObject *name, int firstlineno,
- PyObject *lnotab)
+ PyObject *linetable)
{
return PyCode_NewWithPosOnlyArgs(argcount, 0, kwonlyargcount, nlocals,
stacksize, flags, code, consts, names,
varnames, freevars, cellvars, filename,
- name, firstlineno, lnotab);
+ name, firstlineno, linetable);
}
int
@@ -294,15 +294,15 @@ _PyCode_InitOpcache(PyCodeObject *co)
return -1;
}
- _Py_CODEUNIT *opcodes = (_Py_CODEUNIT*)PyBytes_AS_STRING(co->co_code);
+ const _Py_CODEUNIT *opcodes = (_Py_CODEUNIT*)PyBytes_AS_STRING(co->co_code);
Py_ssize_t opts = 0;
for (Py_ssize_t i = 0; i < co_size;) {
unsigned char opcode = _Py_OPCODE(opcodes[i]);
i++; // 'i' is now aligned to (next_instr - first_instr)
- // TODO: LOAD_METHOD, LOAD_ATTR
- if (opcode == LOAD_GLOBAL) {
+ // TODO: LOAD_METHOD
+ if (opcode == LOAD_GLOBAL || opcode == LOAD_ATTR) {
opts++;
co->co_opcache_map[i] = (unsigned char)opts;
if (opts > 254) {
@@ -314,12 +314,12 @@ _PyCode_InitOpcache(PyCodeObject *co)
if (opts) {
co->co_opcache = (_PyOpcache *)PyMem_Calloc(opts, sizeof(_PyOpcache));
if (co->co_opcache == NULL) {
- PyMem_FREE(co->co_opcache_map);
+ PyMem_Free(co->co_opcache_map);
return -1;
}
}
else {
- PyMem_FREE(co->co_opcache_map);
+ PyMem_Free(co->co_opcache_map);
co->co_opcache_map = NULL;
co->co_opcache = NULL;
}
@@ -369,7 +369,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
filename_ob, /* filename */
funcname_ob, /* name */
firstlineno, /* firstlineno */
- emptystring /* lnotab */
+ emptystring /* linetable */
);
failed:
@@ -395,11 +395,89 @@ static PyMemberDef code_memberlist[] = {
{"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY},
{"co_filename", T_OBJECT, OFF(co_filename), READONLY},
{"co_name", T_OBJECT, OFF(co_name), READONLY},
- {"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
- {"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY},
+ {"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
+ {"co_linetable", T_OBJECT, OFF(co_linetable), READONLY},
{NULL} /* Sentinel */
};
+static int
+emit_pair(PyObject **bytes, int *offset, int a, int b)
+{
+ Py_ssize_t len = PyBytes_GET_SIZE(*bytes);
+ if (*offset + 2 >= len) {
+ if (_PyBytes_Resize(bytes, len * 2) < 0)
+ return 0;
+ }
+ unsigned char *lnotab = (unsigned char *) PyBytes_AS_STRING(*bytes);
+ lnotab += *offset;
+ *lnotab++ = a;
+ *lnotab++ = b;
+ *offset += 2;
+ return 1;
+}
+
+static int
+emit_delta(PyObject **bytes, int bdelta, int ldelta, int *offset)
+{
+ while (bdelta > 255) {
+ if (!emit_pair(bytes, offset, 255, 0)) {
+ return 0;
+ }
+ bdelta -= 255;
+ }
+ while (ldelta > 127) {
+ if (!emit_pair(bytes, offset, bdelta, 127)) {
+ return 0;
+ }
+ bdelta = 0;
+ ldelta -= 127;
+ }
+ while (ldelta < -128) {
+ if (!emit_pair(bytes, offset, bdelta, -128)) {
+ return 0;
+ }
+ bdelta = 0;
+ ldelta += 128;
+ }
+ return emit_pair(bytes, offset, bdelta, ldelta);
+}
+
+static PyObject *
+code_getlnotab(PyCodeObject *code, void *closure)
+{
+ PyCodeAddressRange bounds;
+ PyObject *bytes;
+ int table_offset = 0;
+ int code_offset = 0;
+ int line = code->co_firstlineno;
+ bytes = PyBytes_FromStringAndSize(NULL, 64);
+ if (bytes == NULL) {
+ return NULL;
+ }
+ _PyCode_InitAddressRange(code, &bounds);
+ while (PyLineTable_NextAddressRange(&bounds)) {
+ if (bounds.opaque.computed_line != line) {
+ int bdelta = bounds.ar_start - code_offset;
+ int ldelta = bounds.opaque.computed_line - line;
+ if (!emit_delta(&bytes, bdelta, ldelta, &table_offset)) {
+ Py_DECREF(bytes);
+ return NULL;
+ }
+ code_offset = bounds.ar_start;
+ line = bounds.opaque.computed_line;
+ }
+ }
+ _PyBytes_Resize(&bytes, table_offset);
+ return bytes;
+}
+
+
+static PyGetSetDef code_getsetlist[] = {
+ {"co_lnotab", (getter)code_getlnotab, NULL, NULL},
+ {0}
+};
+
+
/* Helper for code_new: return a shallow copy of a tuple that is
guaranteed to contain exact strings, by converting string subclasses
to exact strings and complaining if a non-string is found. */
@@ -442,46 +520,45 @@ validate_and_copy_tuple(PyObject *tup)
return newtuple;
}
-PyDoc_STRVAR(code_doc,
-"code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n\
- flags, codestring, constants, names, varnames, filename, name,\n\
- firstlineno, lnotab[, freevars[, cellvars]])\n\
-\n\
-Create a code object. Not for the faint of heart.");
+/*[clinic input]
+@classmethod
+code.__new__ as code_new
+
+ argcount: int
+ posonlyargcount: int
+ kwonlyargcount: int
+ nlocals: int
+ stacksize: int
+ flags: int
+ codestring as code: object(subclass_of="&PyBytes_Type")
+ constants as consts: object(subclass_of="&PyTuple_Type")
+ names: object(subclass_of="&PyTuple_Type")
+ varnames: object(subclass_of="&PyTuple_Type")
+ filename: unicode
+ name: unicode
+ firstlineno: int
+ linetable: object(subclass_of="&PyBytes_Type")
+ freevars: object(subclass_of="&PyTuple_Type", c_default="NULL") = ()
+ cellvars: object(subclass_of="&PyTuple_Type", c_default="NULL") = ()
+ /
+
+Create a code object. Not for the faint of heart.
+[clinic start generated code]*/
static PyObject *
-code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount,
+ int kwonlyargcount, int nlocals, int stacksize, int flags,
+ PyObject *code, PyObject *consts, PyObject *names,
+ PyObject *varnames, PyObject *filename, PyObject *name,
+ int firstlineno, PyObject *linetable, PyObject *freevars,
+ PyObject *cellvars)
+/*[clinic end generated code: output=42c1839b082ba293 input=0ec80da632b99f57]*/
{
- int argcount;
- int posonlyargcount;
- int kwonlyargcount;
- int nlocals;
- int stacksize;
- int flags;
PyObject *co = NULL;
- PyObject *code;
- PyObject *consts;
- PyObject *names, *ournames = NULL;
- PyObject *varnames, *ourvarnames = NULL;
- PyObject *freevars = NULL, *ourfreevars = NULL;
- PyObject *cellvars = NULL, *ourcellvars = NULL;
- PyObject *filename;
- PyObject *name;
- int firstlineno;
- PyObject *lnotab;
-
- if (!PyArg_ParseTuple(args, "iiiiiiSO!O!O!UUiS|O!O!:code",
- &argcount, &posonlyargcount, &kwonlyargcount,
- &nlocals, &stacksize, &flags,
- &code,
- &PyTuple_Type, &consts,
- &PyTuple_Type, &names,
- &PyTuple_Type, &varnames,
- &filename, &name,
- &firstlineno, &lnotab,
- &PyTuple_Type, &freevars,
- &PyTuple_Type, &cellvars))
- return NULL;
+ PyObject *ournames = NULL;
+ PyObject *ourvarnames = NULL;
+ PyObject *ourfreevars = NULL;
+ PyObject *ourcellvars = NULL;
if (PySys_Audit("code.__new__", "OOOiiiiii",
code, filename, name, argcount, posonlyargcount,
@@ -541,7 +618,7 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
code, consts, ournames,
ourvarnames, ourfreevars,
ourcellvars, filename,
- name, firstlineno, lnotab);
+ name, firstlineno, linetable);
cleanup:
Py_XDECREF(ournames);
Py_XDECREF(ourvarnames);
@@ -554,10 +631,10 @@ static void
code_dealloc(PyCodeObject *co)
{
if (co->co_opcache != NULL) {
- PyMem_FREE(co->co_opcache);
+ PyMem_Free(co->co_opcache);
}
if (co->co_opcache_map != NULL) {
- PyMem_FREE(co->co_opcache_map);
+ PyMem_Free(co->co_opcache_map);
}
co->co_opcache_flag = 0;
co->co_opcache_size = 0;
@@ -585,14 +662,14 @@ code_dealloc(PyCodeObject *co)
Py_XDECREF(co->co_cellvars);
Py_XDECREF(co->co_filename);
Py_XDECREF(co->co_name);
- Py_XDECREF(co->co_lnotab);
+ Py_XDECREF(co->co_linetable);
if (co->co_cell2arg != NULL)
- PyMem_FREE(co->co_cell2arg);
+ PyMem_Free(co->co_cell2arg);
if (co->co_zombieframe != NULL)
PyObject_GC_Del(co->co_zombieframe);
if (co->co_weakreflist != NULL)
PyObject_ClearWeakRefs((PyObject*)co);
- PyObject_DEL(co);
+ PyObject_Free(co);
}
static PyObject *
@@ -637,7 +714,7 @@ code.replace
co_cellvars: object(subclass_of="&PyTuple_Type", c_default="self->co_cellvars") = None
co_filename: unicode(c_default="self->co_filename") = None
co_name: unicode(c_default="self->co_name") = None
- co_lnotab: PyBytesObject(c_default="(PyBytesObject *)self->co_lnotab") = None
+ co_linetable: PyBytesObject(c_default="(PyBytesObject *)self->co_linetable") = None
Return a copy of the code object with new values for the specified fields.
[clinic start generated code]*/
@@ -650,8 +727,8 @@ code_replace_impl(PyCodeObject *self, int co_argcount,
PyObject *co_consts, PyObject *co_names,
PyObject *co_varnames, PyObject *co_freevars,
PyObject *co_cellvars, PyObject *co_filename,
- PyObject *co_name, PyBytesObject *co_lnotab)
-/*[clinic end generated code: output=25c8e303913bcace input=d9051bc8f24e6b28]*/
+ PyObject *co_name, PyBytesObject *co_linetable)
+/*[clinic end generated code: output=50d77e668d3b449b input=a5f997b173d7f636]*/
{
#define CHECK_INT_ARG(ARG) \
if (ARG < 0) { \
@@ -681,7 +758,7 @@ code_replace_impl(PyCodeObject *self, int co_argcount,
co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals,
co_stacksize, co_flags, (PyObject*)co_code, co_consts, co_names,
co_varnames, co_freevars, co_cellvars, co_filename, co_name,
- co_firstlineno, (PyObject*)co_lnotab);
+ co_firstlineno, (PyObject*)co_linetable);
}
static PyObject *
@@ -934,10 +1011,188 @@ code_hash(PyCodeObject *co)
return h;
}
+typedef struct {
+ PyObject_HEAD
+ PyCodeObject *li_code;
+ PyCodeAddressRange li_line;
+ char *li_end;
+} lineiterator;
+
+
+static void
+lineiter_dealloc(lineiterator *li)
+{
+ Py_DECREF(li->li_code);
+ Py_TYPE(li)->tp_free(li);
+}
+
+static PyObject *
+lineiter_next(lineiterator *li)
+{
+ PyCodeAddressRange *bounds = &li->li_line;
+ if (!PyLineTable_NextAddressRange(bounds)) {
+ return NULL;
+ }
+ PyObject *start = NULL;
+ PyObject *end = NULL;
+ PyObject *line = NULL;
+ PyObject *result = PyTuple_New(3);
+ start = PyLong_FromLong(bounds->ar_start);
+ end = PyLong_FromLong(bounds->ar_end);
+ if (bounds->ar_line < 0) {
+ Py_INCREF(Py_None);
+ line = Py_None;
+ }
+ else {
+ line = PyLong_FromLong(bounds->ar_line);
+ }
+ if (result == NULL || start == NULL || end == NULL || line == NULL) {
+ goto error;
+ }
+ PyTuple_SET_ITEM(result, 0, start);
+ PyTuple_SET_ITEM(result, 1, end);
+ PyTuple_SET_ITEM(result, 2, line);
+ return result;
+error:
+ Py_XDECREF(start);
+ Py_XDECREF(end);
+ Py_XDECREF(line);
+ Py_XDECREF(result);
+ return result;
+}
+
+static PyTypeObject LineIterator = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "line_iterator", /* tp_name */
+ sizeof(lineiterator), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ /* methods */
+ (destructor)lineiter_dealloc, /* tp_dealloc */
+ 0, /* tp_vectorcall_offset */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_as_async */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+ 0, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ PyObject_SelfIter, /* tp_iter */
+ (iternextfunc)lineiter_next, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+ PyObject_Del, /* tp_free */
+};
+
+static PyObject *
+code_linesiterator(PyCodeObject *code, PyObject *Py_UNUSED(args))
+{
+ lineiterator *li = (lineiterator *)PyType_GenericAlloc(&LineIterator, 0);
+ if (li == NULL) {
+ return NULL;
+ }
+ Py_INCREF(code);
+ li->li_code = code;
+ _PyCode_InitAddressRange(code, &li->li_line);
+ return (PyObject *)li;
+}
+
+static void
+retreat(PyCodeAddressRange *bounds)
+{
+ int ldelta = ((signed char *)bounds->opaque.lo_next)[-1];
+ if (ldelta == -128) {
+ ldelta = 0;
+ }
+ bounds->opaque.computed_line -= ldelta;
+ bounds->opaque.lo_next -= 2;
+ bounds->ar_end = bounds->ar_start;
+ bounds->ar_start -= ((unsigned char *)bounds->opaque.lo_next)[-2];
+ ldelta = ((signed char *)bounds->opaque.lo_next)[-1];
+ if (ldelta == -128) {
+ bounds->ar_line = -1;
+ }
+ else {
+ bounds->ar_line = bounds->opaque.computed_line;
+ }
+}
+
+static void
+advance(PyCodeAddressRange *bounds)
+{
+ bounds->ar_start = bounds->ar_end;
+ int delta = ((unsigned char *)bounds->opaque.lo_next)[0];
+ bounds->ar_end += delta;
+ int ldelta = ((signed char *)bounds->opaque.lo_next)[1];
+ bounds->opaque.lo_next += 2;
+ if (ldelta == -128) {
+ bounds->ar_line = -1;
+ }
+ else {
+ bounds->opaque.computed_line += ldelta;
+ bounds->ar_line = bounds->opaque.computed_line;
+ }
+}
+
+static inline int
+at_end(PyCodeAddressRange *bounds) {
+ return bounds->opaque.lo_next >= bounds->opaque.limit;
+}
+
+int
+PyLineTable_PreviousAddressRange(PyCodeAddressRange *range)
+{
+ if (range->ar_start <= 0) {
+ return 0;
+ }
+ retreat(range);
+ while (range->ar_start == range->ar_end) {
+ assert(range->ar_start > 0);
+ retreat(range);
+ }
+ return 1;
+}
+
+int
+PyLineTable_NextAddressRange(PyCodeAddressRange *range)
+{
+ if (at_end(range)) {
+ return 0;
+ }
+ advance(range);
+ while (range->ar_start == range->ar_end && !at_end(range)) {
+ assert(!at_end(range));
+ advance(range);
+ }
+ return 1;
+}
+
+
/* XXX code objects need to participate in GC? */
static struct PyMethodDef code_methods[] = {
{"__sizeof__", (PyCFunction)code_sizeof, METH_NOARGS},
+ {"co_lines", (PyCFunction)code_linesiterator, METH_NOARGS},
CODE_REPLACE_METHODDEF
{NULL, NULL} /* sentinel */
};
@@ -963,7 +1218,7 @@ PyTypeObject PyCode_Type = {
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
- code_doc, /* tp_doc */
+ code_new__doc__, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
code_richcompare, /* tp_richcompare */
@@ -972,7 +1227,7 @@ PyTypeObject PyCode_Type = {
0, /* tp_iternext */
code_methods, /* tp_methods */
code_memberlist, /* tp_members */
- 0, /* tp_getset */
+ code_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
@@ -983,78 +1238,58 @@ PyTypeObject PyCode_Type = {
code_new, /* tp_new */
};
-/* Use co_lnotab to compute the line number from a bytecode index, addrq. See
+/* Use co_linetable to compute the line number from a bytecode index, addrq. See
lnotab_notes.txt for the details of the lnotab representation.
*/
int
PyCode_Addr2Line(PyCodeObject *co, int addrq)
{
- Py_ssize_t size = PyBytes_Size(co->co_lnotab) / 2;
- unsigned char *p = (unsigned char*)PyBytes_AsString(co->co_lnotab);
- int line = co->co_firstlineno;
- int addr = 0;
- while (--size >= 0) {
- addr += *p++;
- if (addr > addrq)
- break;
- line += (signed char)*p;
- p++;
- }
- return line;
+ if (addrq < 0) {
+ return co->co_firstlineno;
+ }
+ assert(addrq >= 0 && addrq < PyBytes_GET_SIZE(co->co_code));
+ PyCodeAddressRange bounds;
+ _PyCode_InitAddressRange(co, &bounds);
+ return _PyCode_CheckLineNumber(addrq, &bounds);
+}
+
+void
+PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int firstlineno, PyCodeAddressRange *range)
+{
+ range->opaque.lo_next = linetable;
+ range->opaque.limit = range->opaque.lo_next + length;
+ range->ar_start = -1;
+ range->ar_end = 0;
+ range->opaque.computed_line = firstlineno;
+ range->ar_line = -1;
+}
+
+int
+_PyCode_InitAddressRange(PyCodeObject* co, PyCodeAddressRange *bounds)
+{
+ const char *linetable = PyBytes_AS_STRING(co->co_linetable);
+ Py_ssize_t length = PyBytes_GET_SIZE(co->co_linetable);
+ PyLineTable_InitAddressRange(linetable, length, co->co_firstlineno, bounds);
+ return bounds->ar_line;
}
/* Update *bounds to describe the first and one-past-the-last instructions in
- the same line as lasti. Return the number of that line. */
+ the same line as lasti. Return the number of that line, or -1 if lasti is out of bounds. */
int
-_PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds)
+_PyCode_CheckLineNumber(int lasti, PyCodeAddressRange *bounds)
{
- Py_ssize_t size;
- int addr, line;
- unsigned char* p;
-
- p = (unsigned char*)PyBytes_AS_STRING(co->co_lnotab);
- size = PyBytes_GET_SIZE(co->co_lnotab) / 2;
-
- addr = 0;
- line = co->co_firstlineno;
- assert(line > 0);
-
- /* possible optimization: if f->f_lasti == instr_ub
- (likely to be a common case) then we already know
- instr_lb -- if we stored the matching value of p
- somewhere we could skip the first while loop. */
-
- /* See lnotab_notes.txt for the description of
- co_lnotab. A point to remember: increments to p
- come in (addr, line) pairs. */
-
- bounds->ap_lower = 0;
- while (size > 0) {
- if (addr + *p > lasti)
- break;
- addr += *p++;
- if ((signed char)*p)
- bounds->ap_lower = addr;
- line += (signed char)*p;
- p++;
- --size;
- }
-
- if (size > 0) {
- while (--size >= 0) {
- addr += *p++;
- if ((signed char)*p)
- break;
- p++;
+ while (bounds->ar_end <= lasti) {
+ if (!PyLineTable_NextAddressRange(bounds)) {
+ return -1;
}
- bounds->ap_upper = addr;
}
- else {
- bounds->ap_upper = INT_MAX;
+ while (bounds->ar_start > lasti) {
+ if (!PyLineTable_PreviousAddressRange(bounds)) {
+ return -1;
+ }
}
-
- return line;
+ return bounds->ar_line;
}