GH-88116: Use a compact format to represent end line and column offsets. (GH-91666)

* Stores all location info in linetable to conform to PEP 626.

* Remove column table from code objects.

* Remove end-line table from code objects.

* Document new location table format
This commit is contained in:
Mark Shannon 2022-04-21 16:10:37 +01:00 committed by GitHub
parent 2a5f171759
commit 944fffee89
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
20 changed files with 859 additions and 539 deletions

View file

@ -244,10 +244,6 @@ _PyCode_Validate(struct _PyCodeConstructor *con)
con->qualname == NULL || !PyUnicode_Check(con->qualname) ||
con->filename == NULL || !PyUnicode_Check(con->filename) ||
con->linetable == NULL || !PyBytes_Check(con->linetable) ||
con->endlinetable == NULL ||
(con->endlinetable != Py_None && !PyBytes_Check(con->endlinetable)) ||
con->columntable == NULL ||
(con->columntable != Py_None && !PyBytes_Check(con->columntable)) ||
con->exceptiontable == NULL || !PyBytes_Check(con->exceptiontable)
) {
PyErr_BadInternalCall();
@ -307,10 +303,6 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
co->co_firstlineno = con->firstlineno;
Py_INCREF(con->linetable);
co->co_linetable = con->linetable;
Py_INCREF(con->endlinetable);
co->co_endlinetable = con->endlinetable;
Py_INCREF(con->columntable);
co->co_columntable = con->columntable;
Py_INCREF(con->consts);
co->co_consts = con->consts;
@ -347,6 +339,97 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
PyBytes_GET_SIZE(con->code));
}
static int
scan_varint(const uint8_t *ptr)
{
int read = *ptr++;
int val = read & 63;
int shift = 0;
while (read & 64) {
read = *ptr++;
shift += 6;
val |= (read & 63) << shift;
}
return val;
}
static int
scan_signed_varint(const uint8_t *ptr)
{
int uval = scan_varint(ptr);
if (uval & 1) {
return -(int)(uval >> 1);
}
else {
return uval >> 1;
}
}
static int
get_line_delta(const uint8_t *ptr)
{
int code = ((*ptr) >> 3) & 15;
switch (code) {
case PY_CODE_LOCATION_INFO_NONE:
return 0;
case PY_CODE_LOCATION_INFO_NO_COLUMNS:
case PY_CODE_LOCATION_INFO_LONG:
return scan_signed_varint(ptr+1);
case PY_CODE_LOCATION_INFO_ONE_LINE0:
return 0;
case PY_CODE_LOCATION_INFO_ONE_LINE1:
return 1;
case PY_CODE_LOCATION_INFO_ONE_LINE2:
return 2;
default:
/* Same line */
return 0;
}
}
static PyObject *
remove_column_info(PyObject *locations)
{
int offset = 0;
const uint8_t *data = (const uint8_t *)PyBytes_AS_STRING(locations);
PyObject *res = PyBytes_FromStringAndSize(NULL, 32);
if (res == NULL) {
PyErr_NoMemory();
return NULL;
}
uint8_t *output = (uint8_t *)PyBytes_AS_STRING(res);
while (offset < PyBytes_GET_SIZE(locations)) {
Py_ssize_t write_offset = output - (uint8_t *)PyBytes_AS_STRING(res);
if (write_offset + 16 >= PyBytes_GET_SIZE(res)) {
if (_PyBytes_Resize(&res, PyBytes_GET_SIZE(res) * 2) < 0) {
return NULL;
}
output = (uint8_t *)PyBytes_AS_STRING(res) + write_offset;
}
int code = (data[offset] >> 3) & 15;
if (code == PY_CODE_LOCATION_INFO_NONE) {
*output++ = data[offset];
}
else {
int blength = (data[offset] & 7)+1;
output += write_location_entry_start(
output, PY_CODE_LOCATION_INFO_NO_COLUMNS, blength);
int ldelta = get_line_delta(&data[offset]);
output += write_signed_varint(output, ldelta);
}
offset++;
while (offset < PyBytes_GET_SIZE(locations) &&
(data[offset] & 128) == 0) {
offset++;
}
}
Py_ssize_t write_offset = output - (uint8_t *)PyBytes_AS_STRING(res);
if (_PyBytes_Resize(&res, write_offset)) {
return NULL;
}
return res;
}
/* The caller is responsible for ensuring that the given data is valid. */
PyCodeObject *
@ -373,21 +456,26 @@ _PyCode_New(struct _PyCodeConstructor *con)
return NULL;
}
// Discard the endlinetable and columntable if we are opted out of debug
PyObject *replacement_locations = NULL;
// Compact the linetable if we are opted out of debug
// ranges.
if (!_Py_GetConfig()->code_debug_ranges) {
con->endlinetable = Py_None;
con->columntable = Py_None;
replacement_locations = remove_column_info(con->linetable);
if (replacement_locations == NULL) {
return NULL;
}
con->linetable = replacement_locations;
}
Py_ssize_t size = PyBytes_GET_SIZE(con->code) / sizeof(_Py_CODEUNIT);
PyCodeObject *co = PyObject_NewVar(PyCodeObject, &PyCode_Type, size);
if (co == NULL) {
Py_XDECREF(replacement_locations);
PyErr_NoMemory();
return NULL;
}
init_code(co, con);
Py_XDECREF(replacement_locations);
return co;
}
@ -403,8 +491,8 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
PyObject *filename, PyObject *name,
PyObject *qualname, int firstlineno,
PyObject *linetable, PyObject *endlinetable,
PyObject *columntable, PyObject *exceptiontable)
PyObject *linetable,
PyObject *exceptiontable)
{
PyCodeObject *co = NULL;
PyObject *localsplusnames = NULL;
@ -482,8 +570,6 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
.code = code,
.firstlineno = firstlineno,
.linetable = linetable,
.endlinetable = endlinetable,
.columntable = columntable,
.consts = consts,
.names = names,
@ -528,14 +614,16 @@ PyCode_New(int argcount, int kwonlyargcount,
PyObject *code, PyObject *consts, PyObject *names,
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
PyObject *filename, PyObject *name, PyObject *qualname,
int firstlineno, PyObject *linetable, PyObject *endlinetable,
PyObject *columntable, PyObject *exceptiontable)
int firstlineno,
PyObject *linetable,
PyObject *exceptiontable)
{
return PyCode_NewWithPosOnlyArgs(argcount, 0, kwonlyargcount, nlocals,
stacksize, flags, code, consts, names,
varnames, freevars, cellvars, filename,
name, qualname, firstlineno, linetable,
endlinetable, columntable, exceptiontable);
name, qualname, firstlineno,
linetable,
exceptiontable);
}
PyCodeObject *
@ -567,8 +655,6 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
.code = emptystring,
.firstlineno = firstlineno,
.linetable = emptystring,
.endlinetable = emptystring,
.columntable = emptystring,
.consts = nulltuple,
.names = nulltuple,
.localsplusnames = nulltuple,
@ -605,68 +691,10 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq)
return _PyCode_CheckLineNumber(addrq, &bounds);
}
int
PyCode_Addr2Location(PyCodeObject *co, int addrq,
int *start_line, int *start_column,
int *end_line, int *end_column)
{
*start_line = PyCode_Addr2Line(co, addrq);
*start_column = _PyCode_Addr2Offset(co, addrq);
*end_line = _PyCode_Addr2EndLine(co, addrq);
*end_column = _PyCode_Addr2EndOffset(co, addrq);
return 1;
}
int
_PyCode_Addr2EndLine(PyCodeObject* co, int addrq)
{
if (addrq < 0) {
return co->co_firstlineno;
}
else if (co->co_endlinetable == Py_None) {
return -1;
}
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
PyCodeAddressRange bounds;
_PyCode_InitEndAddressRange(co, &bounds);
return _PyCode_CheckLineNumber(addrq, &bounds);
}
int
_PyCode_Addr2Offset(PyCodeObject* co, int addrq)
{
if (co->co_columntable == Py_None || addrq < 0) {
return -1;
}
addrq /= sizeof(_Py_CODEUNIT);
if (addrq*2 >= PyBytes_GET_SIZE(co->co_columntable)) {
return -1;
}
unsigned char* bytes = (unsigned char*)PyBytes_AS_STRING(co->co_columntable);
return bytes[addrq*2] - 1;
}
int
_PyCode_Addr2EndOffset(PyCodeObject* co, int addrq)
{
if (co->co_columntable == Py_None || addrq < 0) {
return -1;
}
addrq /= sizeof(_Py_CODEUNIT);
if (addrq*2+1 >= PyBytes_GET_SIZE(co->co_columntable)) {
return -1;
}
unsigned char* bytes = (unsigned char*)PyBytes_AS_STRING(co->co_columntable);
return bytes[addrq*2+1] - 1;
}
void
_PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int firstlineno, PyCodeAddressRange *range)
{
range->opaque.lo_next = linetable;
range->opaque.lo_next = (const uint8_t *)linetable;
range->opaque.limit = range->opaque.lo_next + length;
range->ar_start = -1;
range->ar_end = 0;
@ -677,21 +705,13 @@ _PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int firs
int
_PyCode_InitAddressRange(PyCodeObject* co, PyCodeAddressRange *bounds)
{
assert(co->co_linetable != NULL);
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;
}
int
_PyCode_InitEndAddressRange(PyCodeObject* co, PyCodeAddressRange* bounds)
{
char* linetable = PyBytes_AS_STRING(co->co_endlinetable);
Py_ssize_t length = PyBytes_GET_SIZE(co->co_endlinetable);
_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, or -1 if lasti is out of bounds. */
int
@ -710,43 +730,182 @@ _PyCode_CheckLineNumber(int lasti, PyCodeAddressRange *bounds)
return bounds->ar_line;
}
static int
is_no_line_marker(uint8_t b)
{
return (b >> 3) == 0x1f;
}
#define ASSERT_VALID_BOUNDS(bounds) \
assert(bounds->opaque.lo_next <= bounds->opaque.limit && \
(bounds->ar_line == -1 || bounds->ar_line == bounds->opaque.computed_line) && \
(bounds->opaque.lo_next == bounds->opaque.limit || \
(*bounds->opaque.lo_next) & 128))
static int
next_code_delta(PyCodeAddressRange *bounds)
{
assert((*bounds->opaque.lo_next) & 128);
return (((*bounds->opaque.lo_next) & 7) + 1) * sizeof(_Py_CODEUNIT);
}
static int
previous_code_delta(PyCodeAddressRange *bounds)
{
const uint8_t *ptr = bounds->opaque.lo_next-1;
while (((*ptr) & 128) == 0) {
ptr--;
}
return (((*ptr) & 7) + 1) * sizeof(_Py_CODEUNIT);
}
static int
read_byte(PyCodeAddressRange *bounds)
{
return *bounds->opaque.lo_next++;
}
static int
read_varint(PyCodeAddressRange *bounds)
{
int read = read_byte(bounds);
int val = read & 63;
int shift = 0;
while (read & 64) {
read = read_byte(bounds);
shift += 6;
val |= (read & 63) << shift;
}
return val;
}
static int
read_signed_varint(PyCodeAddressRange *bounds)
{
int uval = read_varint(bounds);
if (uval & 1) {
return -(int)(uval >> 1);
}
else {
return uval >> 1;
}
}
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;
ASSERT_VALID_BOUNDS(bounds);
assert(bounds->ar_start > 0);
do {
bounds->opaque.lo_next--;
} while (((*bounds->opaque.lo_next) & 128) == 0);
bounds->opaque.computed_line -= get_line_delta(bounds->opaque.lo_next);
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_start -= previous_code_delta(bounds);
if (is_no_line_marker(bounds->opaque.lo_next[-1])) {
bounds->ar_line = -1;
}
else {
bounds->ar_line = bounds->opaque.computed_line;
}
ASSERT_VALID_BOUNDS(bounds);
}
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) {
ASSERT_VALID_BOUNDS(bounds);
bounds->opaque.computed_line += get_line_delta(bounds->opaque.lo_next);
if (is_no_line_marker(*bounds->opaque.lo_next)) {
bounds->ar_line = -1;
}
else {
bounds->opaque.computed_line += ldelta;
bounds->ar_line = bounds->opaque.computed_line;
}
bounds->ar_start = bounds->ar_end;
bounds->ar_end += next_code_delta(bounds);
do {
bounds->opaque.lo_next++;
} while (bounds->opaque.lo_next < bounds->opaque.limit &&
((*bounds->opaque.lo_next) & 128) == 0);
ASSERT_VALID_BOUNDS(bounds);
}
static void
advance_with_locations(PyCodeAddressRange *bounds, int *endline, int *column, int *endcolumn)
{
ASSERT_VALID_BOUNDS(bounds);
int first_byte = read_byte(bounds);
int code = (first_byte >> 3) & 15;
bounds->ar_start = bounds->ar_end;
bounds->ar_end = bounds->ar_start + ((first_byte & 7) + 1) * sizeof(_Py_CODEUNIT);
switch(code) {
case PY_CODE_LOCATION_INFO_NONE:
bounds->ar_line = *endline = -1;
*column = *endcolumn = -1;
break;
case PY_CODE_LOCATION_INFO_LONG:
{
bounds->opaque.computed_line += read_signed_varint(bounds);
bounds->ar_line = bounds->opaque.computed_line;
*endline = bounds->ar_line + read_varint(bounds);
*column = read_varint(bounds)-1;
*endcolumn = read_varint(bounds)-1;
break;
}
case PY_CODE_LOCATION_INFO_NO_COLUMNS:
{
/* No column */
bounds->opaque.computed_line += read_signed_varint(bounds);
*endline = bounds->ar_line = bounds->opaque.computed_line;
*column = *endcolumn = -1;
break;
}
case PY_CODE_LOCATION_INFO_ONE_LINE0:
case PY_CODE_LOCATION_INFO_ONE_LINE1:
case PY_CODE_LOCATION_INFO_ONE_LINE2:
{
/* one line form */
int line_delta = code - 10;
bounds->opaque.computed_line += line_delta;
*endline = bounds->ar_line = bounds->opaque.computed_line;
*column = read_byte(bounds);
*endcolumn = read_byte(bounds);
break;
}
default:
{
/* Short forms */
int second_byte = read_byte(bounds);
assert((second_byte & 128) == 0);
*endline = bounds->ar_line = bounds->opaque.computed_line;
*column = code << 3 | (second_byte >> 4);
*endcolumn = *column + (second_byte & 15);
}
}
ASSERT_VALID_BOUNDS(bounds);
}
int
PyCode_Addr2Location(PyCodeObject *co, int addrq,
int *start_line, int *start_column,
int *end_line, int *end_column)
{
if (addrq < 0) {
*start_line = *end_line = co->co_firstlineno;
*start_column = *end_column = 0;
}
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
PyCodeAddressRange bounds;
_PyCode_InitAddressRange(co, &bounds);
_PyCode_CheckLineNumber(addrq, &bounds);
retreat(&bounds);
advance_with_locations(&bounds, end_line, start_column, end_column);
*start_line = bounds.ar_line;
return 1;
}
static inline int
at_end(PyCodeAddressRange *bounds) {
return bounds->opaque.lo_next >= bounds->opaque.limit;
@ -759,10 +918,7 @@ _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range)
return 0;
}
retreat(range);
while (range->ar_start == range->ar_end) {
assert(range->ar_start > 0);
retreat(range);
}
assert(range->ar_end > range->ar_start);
return 1;
}
@ -773,13 +929,37 @@ _PyLineTable_NextAddressRange(PyCodeAddressRange *range)
return 0;
}
advance(range);
while (range->ar_start == range->ar_end) {
assert(!at_end(range));
advance(range);
}
assert(range->ar_end > range->ar_start);
return 1;
}
int
_PyLineTable_StartsLine(PyCodeAddressRange *range)
{
if (range->ar_start <= 0) {
return 0;
}
const uint8_t *ptr = range->opaque.lo_next;
do {
ptr--;
} while (((*ptr) & 128) == 0);
int code = ((*ptr)>> 3) & 15;
switch(code) {
case PY_CODE_LOCATION_INFO_LONG:
return 0;
case PY_CODE_LOCATION_INFO_NO_COLUMNS:
case PY_CODE_LOCATION_INFO_NONE:
return ptr[1] != 0;
case PY_CODE_LOCATION_INFO_ONE_LINE0:
return 0;
case PY_CODE_LOCATION_INFO_ONE_LINE1:
case PY_CODE_LOCATION_INFO_ONE_LINE2:
return 1;
default:
return 0;
}
}
static int
emit_pair(PyObject **bytes, int *offset, int a, int b)
{
@ -856,7 +1036,6 @@ typedef struct {
PyObject_HEAD
PyCodeObject *li_code;
PyCodeAddressRange li_line;
char *li_end;
} lineiterator;
@ -962,7 +1141,11 @@ new_linesiterator(PyCodeObject *code)
typedef struct {
PyObject_HEAD
PyCodeObject* pi_code;
PyCodeAddressRange pi_range;
int pi_offset;
int pi_endline;
int pi_column;
int pi_endcolumn;
} positionsiterator;
static void
@ -983,22 +1166,19 @@ _source_offset_converter(int* value) {
static PyObject*
positionsiter_next(positionsiterator* pi)
{
if (pi->pi_offset >= _PyCode_NBYTES(pi->pi_code)) {
return NULL;
if (pi->pi_offset >= pi->pi_range.ar_end) {
assert(pi->pi_offset == pi->pi_range.ar_end);
if (at_end(&pi->pi_range)) {
return NULL;
}
advance_with_locations(&pi->pi_range, &pi->pi_endline, &pi->pi_column, &pi->pi_endcolumn);
}
int start_line, start_col, end_line, end_col;
if (!PyCode_Addr2Location(pi->pi_code, pi->pi_offset, &start_line,
&start_col, &end_line, &end_col)) {
return NULL;
}
pi->pi_offset += 2;
return Py_BuildValue("(O&O&O&O&)",
_source_offset_converter, &start_line,
_source_offset_converter, &end_line,
_source_offset_converter, &start_col,
_source_offset_converter, &end_col);
_source_offset_converter, &pi->pi_range.ar_line,
_source_offset_converter, &pi->pi_endline,
_source_offset_converter, &pi->pi_column,
_source_offset_converter, &pi->pi_endcolumn);
}
static PyTypeObject PositionsIterator = {
@ -1053,7 +1233,8 @@ code_positionsiterator(PyCodeObject* code, PyObject* Py_UNUSED(args))
}
Py_INCREF(code);
pi->pi_code = code;
pi->pi_offset = 0;
_PyCode_InitAddressRange(code, &pi->pi_range);
pi->pi_offset = pi->pi_range.ar_end;
return (PyObject*)pi;
}
@ -1203,8 +1384,6 @@ code.__new__ as code_new
qualname: unicode
firstlineno: int
linetable: object(subclass_of="&PyBytes_Type")
endlinetable: object
columntable: object
exceptiontable: object(subclass_of="&PyBytes_Type")
freevars: object(subclass_of="&PyTuple_Type", c_default="NULL") = ()
cellvars: object(subclass_of="&PyTuple_Type", c_default="NULL") = ()
@ -1219,10 +1398,9 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount,
PyObject *code, PyObject *consts, PyObject *names,
PyObject *varnames, PyObject *filename, PyObject *name,
PyObject *qualname, int firstlineno, PyObject *linetable,
PyObject *endlinetable, PyObject *columntable,
PyObject *exceptiontable, PyObject *freevars,
PyObject *cellvars)
/*[clinic end generated code: output=e1d2086aa8da7c08 input=a06cd92369134063]*/
/*[clinic end generated code: output=069fa20d299f9dda input=e31da3c41ad8064a]*/
{
PyObject *co = NULL;
PyObject *ournames = NULL;
@ -1263,17 +1441,6 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount,
goto cleanup;
}
if (!Py_IsNone(endlinetable) && !PyBytes_Check(endlinetable)) {
PyErr_SetString(PyExc_ValueError,
"code: endlinetable must be None or bytes");
goto cleanup;
}
if (!Py_IsNone(columntable) && !PyBytes_Check(columntable)) {
PyErr_SetString(PyExc_ValueError,
"code: columntable must be None or bytes");
goto cleanup;
}
ournames = validate_and_copy_tuple(names);
if (ournames == NULL)
goto cleanup;
@ -1300,8 +1467,8 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount,
ourvarnames, ourfreevars,
ourcellvars, filename,
name, qualname, firstlineno,
linetable, endlinetable,
columntable, exceptiontable
linetable,
exceptiontable
);
cleanup:
Py_XDECREF(ournames);
@ -1337,8 +1504,6 @@ code_dealloc(PyCodeObject *co)
Py_XDECREF(co->co_name);
Py_XDECREF(co->co_qualname);
Py_XDECREF(co->co_linetable);
Py_XDECREF(co->co_endlinetable);
Py_XDECREF(co->co_columntable);
Py_XDECREF(co->co_exceptiontable);
if (co->co_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject*)co);
@ -1488,8 +1653,6 @@ static PyMemberDef code_memberlist[] = {
{"co_qualname", T_OBJECT, OFF(co_qualname), READONLY},
{"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
{"co_linetable", T_OBJECT, OFF(co_linetable), READONLY},
{"co_endlinetable", T_OBJECT, OFF(co_endlinetable), READONLY},
{"co_columntable", T_OBJECT, OFF(co_columntable), READONLY},
{"co_exceptiontable", T_OBJECT, OFF(co_exceptiontable), READONLY},
{NULL} /* Sentinel */
};
@ -1585,8 +1748,6 @@ code.replace
co_name: unicode(c_default="self->co_name") = None
co_qualname: unicode(c_default="self->co_qualname") = None
co_linetable: PyBytesObject(c_default="(PyBytesObject *)self->co_linetable") = None
co_endlinetable: object(c_default="self->co_endlinetable") = None
co_columntable: object(c_default="self->co_columntable") = None
co_exceptiontable: PyBytesObject(c_default="(PyBytesObject *)self->co_exceptiontable") = None
Return a copy of the code object with new values for the specified fields.
@ -1601,9 +1762,9 @@ code_replace_impl(PyCodeObject *self, int co_argcount,
PyObject *co_varnames, PyObject *co_freevars,
PyObject *co_cellvars, PyObject *co_filename,
PyObject *co_name, PyObject *co_qualname,
PyBytesObject *co_linetable, PyObject *co_endlinetable,
PyObject *co_columntable, PyBytesObject *co_exceptiontable)
/*[clinic end generated code: output=f046bf0be3bab91f input=78dbe204dbd06c2f]*/
PyBytesObject *co_linetable,
PyBytesObject *co_exceptiontable)
/*[clinic end generated code: output=b6cd9988391d5711 input=f6f68e03571f8d7c]*/
{
#define CHECK_INT_ARG(ARG) \
if (ARG < 0) { \
@ -1664,24 +1825,12 @@ code_replace_impl(PyCodeObject *self, int co_argcount,
co_freevars = freevars;
}
if (!Py_IsNone(co_endlinetable) && !PyBytes_Check(co_endlinetable)) {
PyErr_SetString(PyExc_ValueError,
"co_endlinetable must be None or bytes");
goto error;
}
if (!Py_IsNone(co_columntable) && !PyBytes_Check(co_columntable)) {
PyErr_SetString(PyExc_ValueError,
"co_columntable must be None or bytes");
goto error;
}
co = PyCode_NewWithPosOnlyArgs(
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_qualname, co_firstlineno, (PyObject*)co_linetable,
(PyObject*)co_endlinetable, (PyObject*)co_columntable,
(PyObject*)co_exceptiontable);
co_qualname, co_firstlineno,
(PyObject*)co_linetable, (PyObject*)co_exceptiontable);
error:
Py_XDECREF(code);