diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2021-06-07 18:22:26 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-07 18:22:26 (GMT) |
commit | 2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6 (patch) | |
tree | d3983e5282f575560cb7449fae4785447fdfff14 /Include | |
parent | 001eb520b5757294dc455c900d94b7b153de6cdd (diff) | |
download | cpython-2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6.zip cpython-2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6.tar.gz cpython-2ab27c4af4ddf7528e1375e77c787c7fbb09b5e6.tar.bz2 |
bpo-43693: Un-revert commits 2c1e258 and b2bf2bc. (gh-26577)
These were reverted in gh-26530 (commit 17c4edc) due to refleaks.
* 2c1e258 - Compute deref offsets in compiler (gh-25152)
* b2bf2bc - Add new internal code objects fields: co_fastlocalnames and co_fastlocalkinds. (gh-26388)
This change fixes the refleaks.
https://bugs.python.org/issue43693
Diffstat (limited to 'Include')
-rw-r--r-- | Include/cpython/code.h | 24 | ||||
-rw-r--r-- | Include/internal/pycore_code.h | 63 |
2 files changed, 78 insertions, 9 deletions
diff --git a/Include/cpython/code.h b/Include/cpython/code.h index 98d728b..c81f9f3 100644 --- a/Include/cpython/code.h +++ b/Include/cpython/code.h @@ -3,6 +3,8 @@ #endif typedef uint16_t _Py_CODEUNIT; +// Each oparg must fit in the second half of _Py_CODEUNIT, hence 8 bits. +#define _Py_MAX_OPARG 255 #ifdef WORDS_BIGENDIAN # define _Py_OPCODE(word) ((word) >> 8) @@ -16,6 +18,11 @@ typedef uint16_t _Py_CODEUNIT; typedef struct _PyOpcache _PyOpcache; + +// These are duplicated from pycore_code.h. +typedef unsigned char _PyLocalsPlusKind; +typedef _PyLocalsPlusKind *_PyLocalsPlusKinds; + /* Bytecode object */ struct PyCodeObject { PyObject_HEAD @@ -47,7 +54,9 @@ struct PyCodeObject { // The hottest fields (in the eval loop) are grouped here at the top. PyObject *co_consts; /* list (constants used) */ PyObject *co_names; /* list of strings (names used) */ - _Py_CODEUNIT *co_firstinstr; /* Pointer to first instruction, used for quickening */ + _Py_CODEUNIT *co_firstinstr; /* Pointer to first instruction, used for quickening. + Unlike the other "hot" fields, this one is + actually derived from co_code. */ PyObject *co_exceptiontable; /* Byte string encoding exception handling table */ int co_flags; /* CO_..., see below */ int co_warmup; /* Warmup counter for quickening */ @@ -59,9 +68,8 @@ struct PyCodeObject { int co_stacksize; /* #entries needed for evaluation stack */ int co_firstlineno; /* first source line number */ PyObject *co_code; /* instruction opcodes */ - PyObject *co_varnames; /* tuple of strings (local variable names) */ - PyObject *co_cellvars; /* tuple of strings (cell variable names) */ - PyObject *co_freevars; /* tuple of strings (free variable names) */ + PyObject *co_localsplusnames; /* tuple mapping offsets to names */ + _PyLocalsPlusKinds co_localspluskinds; /* array mapping to local kinds */ 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 @@ -70,11 +78,15 @@ struct PyCodeObject { /* These fields are set with computed values on new code objects. */ int *co_cell2arg; /* Maps cell vars which are arguments. */ - // These are redundant but offer some performance benefit. + // redundant values (derived from co_localsplusnames and co_localspluskinds) int co_nlocalsplus; /* number of local + cell + free variables */ int co_nlocals; /* number of local variables */ int co_ncellvars; /* number of cell variables */ int co_nfreevars; /* number of free variables */ + // lazily-computed values + PyObject *co_varnames; /* tuple of strings (local variable names) */ + PyObject *co_cellvars; /* tuple of strings (cell variable names) */ + PyObject *co_freevars; /* tuple of strings (free variable names) */ /* The remaining fields are zeroed out on new code objects. */ @@ -152,7 +164,7 @@ struct PyCodeObject { PyAPI_DATA(PyTypeObject) PyCode_Type; #define PyCode_Check(op) Py_IS_TYPE(op, &PyCode_Type) -#define PyCode_GetNumFree(op) (PyTuple_GET_SIZE((op)->co_freevars)) +#define PyCode_GetNumFree(op) ((op)->co_nfreevars) /* Public interface */ PyAPI_FUNC(PyCodeObject *) PyCode_New( diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index cb72350..d1ff597 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -150,6 +150,58 @@ int _Py_Quicken(PyCodeObject *code); extern Py_ssize_t _Py_QuickenedCount; + +/* "Locals plus" for a code object is the set of locals + cell vars + + * free vars. This relates to variable names as well as offsets into + * the "fast locals" storage array of execution frames. The compiler + * builds the list of names, their offsets, and the corresponding + * kind of local. + * + * Those kinds represent the source of the initial value and the + * variable's scope (as related to closures). A "local" is an + * argument or other variable defined in the current scope. A "free" + * variable is one that is defined in an outer scope and comes from + * the function's closure. A "cell" variable is a local that escapes + * into an inner function as part of a closure, and thus must be + * wrapped in a cell. Any "local" can also be a "cell", but the + * "free" kind is mutually exclusive with both. + */ + +// We would use an enum if C let us specify the storage type. +typedef unsigned char _PyLocalsPlusKind; +/* Note that these all fit within _PyLocalsPlusKind, 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 + +typedef _PyLocalsPlusKind *_PyLocalsPlusKinds; + +static inline int +_PyCode_InitLocalsPlusKinds(int num, _PyLocalsPlusKinds *pkinds) +{ + if (num == 0) { + *pkinds = NULL; + return 0; + } + _PyLocalsPlusKinds kinds = PyMem_NEW(_PyLocalsPlusKind, num); + if (kinds == NULL) { + PyErr_NoMemory(); + return -1; + } + *pkinds = kinds; + return 0; +} + +static inline void +_PyCode_ClearLocalsPlusKinds(_PyLocalsPlusKinds kinds) +{ + if (kinds != NULL) { + PyMem_Free(kinds); + } +} + struct _PyCodeConstructor { /* metadata */ PyObject *filename; @@ -166,13 +218,13 @@ struct _PyCodeConstructor { PyObject *names; /* mapping frame offsets to information */ - PyObject *varnames; - PyObject *cellvars; - PyObject *freevars; + PyObject *localsplusnames; + _PyLocalsPlusKinds localspluskinds; /* args (within varnames) */ int argcount; int posonlyargcount; + // XXX Replace argcount with posorkwargcount (argcount - posonlyargcount). int kwonlyargcount; /* needed to create the frame */ @@ -199,6 +251,11 @@ PyAPI_FUNC(PyCodeObject *) _PyCode_New(struct _PyCodeConstructor *); int _PyCode_InitOpcache(PyCodeObject *co); +/* Getters for internal PyCodeObject data. */ +PyAPI_FUNC(PyObject *) _PyCode_GetVarnames(PyCodeObject *); +PyAPI_FUNC(PyObject *) _PyCode_GetCellvars(PyCodeObject *); +PyAPI_FUNC(PyObject *) _PyCode_GetFreevars(PyCodeObject *); + #ifdef __cplusplus } |