bpo-43693: Turn localspluskinds into an object (GH-26749)

Managing it as a bare pointer to malloc'ed bytes is just too awkward in a few places.
This commit is contained in:
Guido van Rossum 2021-06-21 13:53:04 -07:00 committed by GitHub
parent c5d700f0e2
commit 355f5dd36a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 5455 additions and 5395 deletions

View File

@ -26,9 +26,6 @@ typedef uint16_t _Py_CODEUNIT;
typedef struct _PyOpcache _PyOpcache;
typedef unsigned char _PyLocalsPlusKind;
typedef _PyLocalsPlusKind *_PyLocalsPlusKinds;
/* Bytecode object */
struct PyCodeObject {
PyObject_HEAD
@ -75,7 +72,7 @@ struct PyCodeObject {
int co_firstlineno; /* first source line number */
PyObject *co_code; /* instruction opcodes */
PyObject *co_localsplusnames; /* tuple mapping offsets to names */
_PyLocalsPlusKinds co_localspluskinds; /* array mapping to local kinds */
PyObject *co_localspluskinds; /* Bytes mapping to local kinds (one byte per variable) */
PyObject *co_filename; /* unicode (where it was loaded from) */
PyObject *co_name; /* unicode (name, for reference) */
PyObject *co_linetable; /* string (encoding addr<->lineno mapping) See
@ -222,4 +219,3 @@ void PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int
int PyLineTable_NextAddressRange(PyCodeAddressRange *range);
int PyLineTable_PreviousAddressRange(PyCodeAddressRange *range);

View File

@ -180,39 +180,34 @@ extern Py_ssize_t _Py_QuickenedCount;
* "free" kind is mutually exclusive with both.
*/
// For now _PyLocalsPlusKind and _PyLocalsPlusKinds are defined
// in Include/cpython/code.h.
/* Note that these all fit within _PyLocalsPlusKind, as do combinations. */
// Note that these all fit within a byte, as do combinations.
// Later, we will use the smaller numbers to differentiate the different
// kinds of locals (e.g. pos-only arg, varkwargs, local-only).
#define CO_FAST_LOCAL 0x20
#define CO_FAST_CELL 0x40
#define CO_FAST_FREE 0x80
static inline int
_PyCode_InitLocalsPlusKinds(int num, _PyLocalsPlusKinds *pkinds)
typedef unsigned char _PyLocals_Kind;
static inline _PyLocals_Kind
_PyLocals_GetKind(PyObject *kinds, int i)
{
if (num == 0) {
*pkinds = NULL;
return 0;
}
_PyLocalsPlusKinds kinds = PyMem_NEW(_PyLocalsPlusKind, num);
if (kinds == NULL) {
PyErr_NoMemory();
return -1;
}
*pkinds = kinds;
return 0;
assert(PyBytes_Check(kinds));
assert(0 <= i && i < PyBytes_GET_SIZE(kinds));
char *ptr = PyBytes_AS_STRING(kinds);
return (_PyLocals_Kind)(ptr[i]);
}
static inline void
_PyCode_ClearLocalsPlusKinds(_PyLocalsPlusKinds kinds)
_PyLocals_SetKind(PyObject *kinds, int i, _PyLocals_Kind kind)
{
if (kinds != NULL) {
PyMem_Free(kinds);
}
assert(PyBytes_Check(kinds));
assert(0 <= i && i < PyBytes_GET_SIZE(kinds));
char *ptr = PyBytes_AS_STRING(kinds);
ptr[i] = (char) kind;
}
struct _PyCodeConstructor {
/* metadata */
PyObject *filename;
@ -229,8 +224,8 @@ struct _PyCodeConstructor {
PyObject *names;
/* mapping frame offsets to information */
PyObject *localsplusnames;
_PyLocalsPlusKinds localspluskinds;
PyObject *localsplusnames; // Tuple of strings
PyObject *localspluskinds; // Bytes object, one byte per variable
/* args (within varnames) */
int argcount;

View File

@ -80,9 +80,9 @@ class PythonValuesTestCase(unittest.TestCase):
continue
items.append((entry.name.decode("ascii"), entry.size))
expected = [("__hello__", 128),
("__phello__", -128),
("__phello__.spam", 128),
expected = [("__hello__", 133),
("__phello__", -133),
("__phello__.spam", 133),
]
self.assertEqual(items, expected, "PyImport_FrozenModules example "
"in Doc/library/ctypes.rst may be out of date")

View File

@ -359,6 +359,7 @@ _code_type = type(_write_atomic.__code__)
# Python 3.11a1 3454 (compute cell offsets relative to locals bpo-43693)
# Python 3.11a1 3455 (add MAKE_CELL bpo-43693)
# Python 3.11a1 3456 (interleave cell args bpo-43693)
# Python 3.11a1 3457 (Change localsplus to a bytes object bpo-43693)
#
# MAGIC must change whenever the bytecode emitted by the compiler may no
@ -368,7 +369,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated.
MAGIC_NUMBER = (3456).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3457).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__'

View File

@ -156,16 +156,16 @@ validate_and_copy_tuple(PyObject *tup)
// This is also used in compile.c.
void
_Py_set_localsplus_info(int offset, PyObject *name, _PyLocalsPlusKind kind,
PyObject *names, _PyLocalsPlusKinds kinds)
_Py_set_localsplus_info(int offset, PyObject *name, _PyLocals_Kind kind,
PyObject *names, PyObject *kinds)
{
Py_INCREF(name);
PyTuple_SET_ITEM(names, offset, name);
kinds[offset] = kind;
_PyLocals_SetKind(kinds, offset, kind);
}
static void
get_localsplus_counts(PyObject *names, _PyLocalsPlusKinds kinds,
get_localsplus_counts(PyObject *names, PyObject *kinds,
int *pnlocals, int *pnplaincellvars, int *pncellvars,
int *pnfreevars)
{
@ -175,17 +175,18 @@ get_localsplus_counts(PyObject *names, _PyLocalsPlusKinds kinds,
int nfreevars = 0;
Py_ssize_t nlocalsplus = PyTuple_GET_SIZE(names);
for (int i = 0; i < nlocalsplus; i++) {
if (kinds[i] & CO_FAST_LOCAL) {
_PyLocals_Kind kind = _PyLocals_GetKind(kinds, i);
if (kind & CO_FAST_LOCAL) {
nlocals += 1;
if (kinds[i] & CO_FAST_CELL) {
if (kind & CO_FAST_CELL) {
ncellvars += 1;
}
}
else if (kinds[i] & CO_FAST_CELL) {
else if (kind & CO_FAST_CELL) {
ncellvars += 1;
nplaincellvars += 1;
}
else if (kinds[i] & CO_FAST_FREE) {
else if (kind & CO_FAST_FREE) {
nfreevars += 1;
}
}
@ -204,7 +205,7 @@ get_localsplus_counts(PyObject *names, _PyLocalsPlusKinds kinds,
}
static PyObject *
get_localsplus_names(PyCodeObject *co, _PyLocalsPlusKind kind, int num)
get_localsplus_names(PyCodeObject *co, _PyLocals_Kind kind, int num)
{
PyObject *names = PyTuple_New(num);
if (names == NULL) {
@ -212,7 +213,8 @@ get_localsplus_names(PyCodeObject *co, _PyLocalsPlusKind kind, int num)
}
int index = 0;
for (int offset = 0; offset < co->co_nlocalsplus; offset++) {
if ((co->co_localspluskinds[offset] & kind) == 0) {
_PyLocals_Kind k = _PyLocals_GetKind(co->co_localspluskinds, offset);
if ((k & kind) == 0) {
continue;
}
assert(index < num);
@ -236,8 +238,9 @@ _PyCode_Validate(struct _PyCodeConstructor *con)
con->consts == NULL || !PyTuple_Check(con->consts) ||
con->names == NULL || !PyTuple_Check(con->names) ||
con->localsplusnames == NULL || !PyTuple_Check(con->localsplusnames) ||
(PyTuple_GET_SIZE(con->localsplusnames) && con->localspluskinds == NULL) ||
(!PyTuple_GET_SIZE(con->localsplusnames) && con->localspluskinds != NULL) ||
con->localspluskinds == NULL || !PyBytes_Check(con->localspluskinds) ||
PyTuple_GET_SIZE(con->localsplusnames)
!= PyBytes_GET_SIZE(con->localspluskinds) ||
con->name == NULL || !PyUnicode_Check(con->name) ||
con->filename == NULL || !PyUnicode_Check(con->filename) ||
con->linetable == NULL || !PyBytes_Check(con->linetable) ||
@ -309,7 +312,7 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
Py_INCREF(con->localsplusnames);
co->co_localsplusnames = con->localsplusnames;
// We take ownership of the kinds array.
Py_INCREF(con->localspluskinds);
co->co_localspluskinds = con->localspluskinds;
co->co_argcount = con->argcount;
@ -394,7 +397,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
{
PyCodeObject *co = NULL;
PyObject *localsplusnames = NULL;
_PyLocalsPlusKinds localspluskinds = NULL;
PyObject *localspluskinds = NULL;
if (varnames == NULL || !PyTuple_Check(varnames) ||
cellvars == NULL || !PyTuple_Check(cellvars) ||
@ -413,7 +416,8 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
if (localsplusnames == NULL) {
goto error;
}
if (_PyCode_InitLocalsPlusKinds(nlocalsplus, &localspluskinds) < 0) {
localspluskinds = PyBytes_FromStringAndSize(NULL, nlocalsplus);
if (localspluskinds == NULL) {
goto error;
}
int offset = 0;
@ -438,7 +442,8 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
// Merge the localsplus indices.
nlocalsplus -= 1;
offset -= 1;
localspluskinds[argoffset] |= CO_FAST_CELL;
_PyLocals_Kind kind = _PyLocals_GetKind(localspluskinds, argoffset);
_PyLocals_SetKind(localspluskinds, argoffset, kind | CO_FAST_CELL);
continue;
}
_Py_set_localsplus_info(offset, name, CO_FAST_CELL,
@ -495,7 +500,6 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
goto error;
}
localspluskinds = NULL; // This keeps it from getting freed below.
Py_INCREF(varnames);
co->co_varnames = varnames;
Py_INCREF(cellvars);
@ -505,7 +509,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
error:
Py_XDECREF(localsplusnames);
_PyCode_ClearLocalsPlusKinds(localspluskinds);
Py_XDECREF(localspluskinds);
return co;
}
@ -558,6 +562,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
.consts = nulltuple,
.names = nulltuple,
.localsplusnames = nulltuple,
.localspluskinds = emptystring,
.exceptiontable = emptystring,
};
result = _PyCode_New(&con);
@ -1142,7 +1147,7 @@ code_dealloc(PyCodeObject *co)
Py_XDECREF(co->co_consts);
Py_XDECREF(co->co_names);
Py_XDECREF(co->co_localsplusnames);
_PyCode_ClearLocalsPlusKinds(co->co_localspluskinds);
Py_XDECREF(co->co_localspluskinds);
Py_XDECREF(co->co_varnames);
Py_XDECREF(co->co_freevars);
Py_XDECREF(co->co_cellvars);

View File

@ -958,7 +958,7 @@ PyFrame_FastToLocalsWithError(PyFrameObject *f)
co = _PyFrame_GetCode(f);
fast = f->f_localsptr;
for (int i = 0; i < co->co_nlocalsplus; i++) {
_PyLocalsPlusKind kind = co->co_localspluskinds[i];
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
/* If the namespace is unoptimized, then one of the
following cases applies:
@ -1052,7 +1052,7 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
PyErr_Fetch(&error_type, &error_value, &error_traceback);
for (int i = 0; i < co->co_nlocalsplus; i++) {
_PyLocalsPlusKind kind = co->co_localspluskinds[i];
_PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
/* Same test as in PyFrame_FastToLocals() above. */
if (kind & CO_FAST_FREE && !(co->co_flags & CO_OPTIMIZED)) {

View File

@ -8864,7 +8864,7 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
PyObject *firstarg = f->f_localsptr[0];
// The first argument might be a cell.
if (firstarg != NULL && (co->co_localspluskinds[0] & CO_FAST_CELL)) {
if (firstarg != NULL && (_PyLocals_GetKind(co->co_localspluskinds, 0) & CO_FAST_CELL)) {
// "firstarg" is a cell here unless (very unlikely) super()
// was called from the C-API before the first MAKE_CELL op.
if (f->f_lasti >= 0) {
@ -8883,7 +8883,7 @@ super_init_without_args(PyFrameObject *f, PyCodeObject *co,
PyTypeObject *type = NULL;
int i = co->co_nlocals + co->co_nplaincellvars;
for (; i < co->co_nlocalsplus; i++) {
assert((co->co_localspluskinds[i] & CO_FAST_FREE) != 0);
assert((_PyLocals_GetKind(co->co_localspluskinds, i) & CO_FAST_FREE) != 0);
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
assert(PyUnicode_Check(name));
if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) {

View File

@ -19,9 +19,9 @@ unsigned char M_test_frozenmain[] = {
121,115,90,17,95,116,101,115,116,105,110,116,101,114,110,97,
108,99,97,112,105,218,5,112,114,105,110,116,218,4,97,114,
103,118,90,11,103,101,116,95,99,111,110,102,105,103,115,114,
2,0,0,0,218,3,107,101,121,169,0,250,18,116,101,115,
116,95,102,114,111,122,101,110,109,97,105,110,46,112,121,218,
8,60,109,111,100,117,108,101,62,1,0,0,0,115,16,0,
0,0,8,3,8,1,8,2,12,1,12,1,8,1,26,7,
4,249,243,0,0,0,0,
2,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0,
250,18,116,101,115,116,95,102,114,111,122,101,110,109,97,105,
110,46,112,121,218,8,60,109,111,100,117,108,101,62,1,0,
0,0,115,16,0,0,0,8,3,8,1,8,2,12,1,12,
1,8,1,26,7,4,249,114,9,0,0,0,
};

View File

@ -7187,15 +7187,13 @@ merge_const_one(struct compiler *c, PyObject **obj)
}
// This is in codeobject.c.
extern void _Py_set_localsplus_info(int, PyObject *, _PyLocalsPlusKind,
PyObject *, _PyLocalsPlusKinds);
extern void _Py_set_localsplus_info(int, PyObject *, unsigned char,
PyObject *, PyObject *);
static void
compute_localsplus_info(struct compiler *c, int nlocalsplus,
PyObject *names, _PyLocalsPlusKinds kinds)
PyObject *names, PyObject *kinds)
{
assert(PyTuple_GET_SIZE(names) == nlocalsplus);
PyObject *k, *v;
Py_ssize_t pos = 0;
while (PyDict_Next(c->u->u_varnames, &pos, &k, &v)) {
@ -7203,7 +7201,7 @@ compute_localsplus_info(struct compiler *c, int nlocalsplus,
assert(offset >= 0);
assert(offset < nlocalsplus);
// For now we do not distinguish arg kinds.
_PyLocalsPlusKind kind = CO_FAST_LOCAL;
_PyLocals_Kind kind = CO_FAST_LOCAL;
if (PyDict_GetItem(c->u->u_cellvars, k) != NULL) {
kind |= CO_FAST_CELL;
}
@ -7245,7 +7243,7 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
PyObject *names = NULL;
PyObject *consts = NULL;
PyObject *localsplusnames = NULL;
_PyLocalsPlusKinds localspluskinds = NULL;
PyObject *localspluskinds = NULL;
PyObject *name = NULL;
names = dict_keys_inorder(c->u->u_names, 0);
@ -7281,7 +7279,8 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
if (localsplusnames == NULL) {
goto error;
}
if (_PyCode_InitLocalsPlusKinds(nlocalsplus, &localspluskinds) < 0) {
localspluskinds = PyBytes_FromStringAndSize(NULL, nlocalsplus);
if (localspluskinds == NULL) {
goto error;
}
compute_localsplus_info(c, nlocalsplus, localsplusnames, localspluskinds);
@ -7315,7 +7314,6 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
}
if (!merge_const_one(c, &localsplusnames)) {
_PyCode_ClearLocalsPlusKinds(con.localspluskinds);
goto error;
}
con.localsplusnames = localsplusnames;
@ -7325,13 +7323,11 @@ makecode(struct compiler *c, struct assembler *a, PyObject *constslist,
goto error;
}
localspluskinds = NULL; // This keeps it from getting freed below.
error:
Py_XDECREF(names);
Py_XDECREF(consts);
Py_XDECREF(localsplusnames);
_PyCode_ClearLocalsPlusKinds(localspluskinds);
Py_XDECREF(localspluskinds);
Py_XDECREF(name);
return co;
}

View File

@ -5,7 +5,8 @@ const unsigned char _Py_M__hello[] = {
100,1,131,1,1,0,100,2,83,0,41,3,84,122,12,72,
101,108,108,111,32,119,111,114,108,100,33,78,41,2,90,11,
105,110,105,116,105,97,108,105,122,101,100,218,5,112,114,105,
110,116,169,0,122,14,60,102,114,111,122,101,110,32,104,101,
108,108,111,62,218,8,60,109,111,100,117,108,101,62,1,0,
0,0,115,4,0,0,0,4,0,12,1,243,0,0,0,0,
110,116,169,0,243,0,0,0,0,122,14,60,102,114,111,122,
101,110,32,104,101,108,108,111,62,218,8,60,109,111,100,117,
108,101,62,1,0,0,0,115,4,0,0,0,4,0,12,1,
114,2,0,0,0,
};

3525
Python/importlib.h generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -519,7 +519,7 @@ w_complex_object(PyObject *v, char flag, WFILE *p)
w_object(co->co_consts, p);
w_object(co->co_names, p);
w_object(co->co_localsplusnames, p);
w_string(co->co_localspluskinds, co->co_nlocalsplus, p);
w_object(co->co_localspluskinds, p);
w_object(co->co_filename, p);
w_object(co->co_name, p);
w_long(co->co_firstlineno, p);
@ -1306,7 +1306,7 @@ r_object(RFILE *p)
PyObject *consts = NULL;
PyObject *names = NULL;
PyObject *localsplusnames = NULL;
_PyLocalsPlusKinds localspluskinds = NULL;
PyObject *localspluskinds = NULL;
PyObject *filename = NULL;
PyObject *name = NULL;
int firstlineno;
@ -1348,19 +1348,9 @@ r_object(RFILE *p)
localsplusnames = r_object(p);
if (localsplusnames == NULL)
goto code_error;
assert(PyTuple_GET_SIZE(localsplusnames) < INT_MAX);
int nlocalsplus = (int)PyTuple_GET_SIZE(localsplusnames);
if (nlocalsplus) {
if (_PyCode_InitLocalsPlusKinds(nlocalsplus,
&localspluskinds) < 0) {
localspluskinds = r_object(p);
if (localspluskinds == NULL)
goto code_error;
}
for (int i = 0; i < nlocalsplus; i++) {
localspluskinds[i] = r_byte(p);
}
}
filename = r_object(p);
if (filename == NULL)
goto code_error;
@ -1377,6 +1367,7 @@ r_object(RFILE *p)
if (exceptiontable == NULL)
goto code_error;
Py_ssize_t nlocalsplus = PyTuple_GET_SIZE(localsplusnames);
if (PySys_Audit("code.__new__", "OOOiiiiii",
code, filename, name, argcount, posonlyargcount,
kwonlyargcount, nlocalsplus, stacksize,
@ -1417,8 +1408,6 @@ r_object(RFILE *p)
goto code_error;
}
localspluskinds = NULL; // This keeps it from getting freed below.
v = r_ref_insert(v, idx, flag, p);
code_error:
@ -1426,7 +1415,7 @@ r_object(RFILE *p)
Py_XDECREF(consts);
Py_XDECREF(names);
Py_XDECREF(localsplusnames);
_PyCode_ClearLocalsPlusKinds(localspluskinds);
Py_XDECREF(localspluskinds);
Py_XDECREF(filename);
Py_XDECREF(name);
Py_XDECREF(linetable);