mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
gh-132775: Add _PyCode_GetVarCounts() (gh-133128)
This helper is useful in a variety of ways, including in demonstrating how the different counts relate to one another. It will be used in a later change to help identify if a function is "stateless", meaning it doesn't have any free vars or globals. Note that a majority of this change is tests.
This commit is contained in:
parent
26c0248b54
commit
94b4fcd806
5 changed files with 689 additions and 0 deletions
|
@ -999,6 +999,172 @@ get_co_localskinds(PyObject *self, PyObject *arg)
|
|||
return kinds;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_code_var_counts(PyObject *self, PyObject *_args, PyObject *_kwargs)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
PyObject *codearg;
|
||||
PyObject *globalnames = NULL;
|
||||
PyObject *attrnames = NULL;
|
||||
PyObject *globalsns = NULL;
|
||||
PyObject *builtinsns = NULL;
|
||||
static char *kwlist[] = {"code", "globalnames", "attrnames", "globalsns",
|
||||
"builtinsns", NULL};
|
||||
if (!PyArg_ParseTupleAndKeywords(_args, _kwargs,
|
||||
"O|OOO!O!:get_code_var_counts", kwlist,
|
||||
&codearg, &globalnames, &attrnames,
|
||||
&PyDict_Type, &globalsns, &PyDict_Type, &builtinsns))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (PyFunction_Check(codearg)) {
|
||||
if (globalsns == NULL) {
|
||||
globalsns = PyFunction_GET_GLOBALS(codearg);
|
||||
}
|
||||
if (builtinsns == NULL) {
|
||||
builtinsns = PyFunction_GET_BUILTINS(codearg);
|
||||
}
|
||||
codearg = PyFunction_GET_CODE(codearg);
|
||||
}
|
||||
else if (!PyCode_Check(codearg)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"argument must be a code object or a function");
|
||||
return NULL;
|
||||
}
|
||||
PyCodeObject *code = (PyCodeObject *)codearg;
|
||||
|
||||
_PyCode_var_counts_t counts = {0};
|
||||
_PyCode_GetVarCounts(code, &counts);
|
||||
if (_PyCode_SetUnboundVarCounts(
|
||||
tstate, code, &counts, globalnames, attrnames,
|
||||
globalsns, builtinsns) < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define SET_COUNT(DICT, STRUCT, NAME) \
|
||||
do { \
|
||||
PyObject *count = PyLong_FromLong(STRUCT.NAME); \
|
||||
int res = PyDict_SetItemString(DICT, #NAME, count); \
|
||||
Py_DECREF(count); \
|
||||
if (res < 0) { \
|
||||
goto error; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
PyObject *locals = NULL;
|
||||
PyObject *args = NULL;
|
||||
PyObject *cells = NULL;
|
||||
PyObject *hidden = NULL;
|
||||
PyObject *unbound = NULL;
|
||||
PyObject *globals = NULL;
|
||||
PyObject *countsobj = PyDict_New();
|
||||
if (countsobj == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
SET_COUNT(countsobj, counts, total);
|
||||
|
||||
// locals
|
||||
locals = PyDict_New();
|
||||
if (locals == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItemString(countsobj, "locals", locals) < 0) {
|
||||
goto error;
|
||||
}
|
||||
SET_COUNT(locals, counts.locals, total);
|
||||
|
||||
// locals.args
|
||||
args = PyDict_New();
|
||||
if (args == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItemString(locals, "args", args) < 0) {
|
||||
goto error;
|
||||
}
|
||||
SET_COUNT(args, counts.locals.args, total);
|
||||
SET_COUNT(args, counts.locals.args, numposonly);
|
||||
SET_COUNT(args, counts.locals.args, numposorkw);
|
||||
SET_COUNT(args, counts.locals.args, numkwonly);
|
||||
SET_COUNT(args, counts.locals.args, varargs);
|
||||
SET_COUNT(args, counts.locals.args, varkwargs);
|
||||
|
||||
// locals.numpure
|
||||
SET_COUNT(locals, counts.locals, numpure);
|
||||
|
||||
// locals.cells
|
||||
cells = PyDict_New();
|
||||
if (cells == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItemString(locals, "cells", cells) < 0) {
|
||||
goto error;
|
||||
}
|
||||
SET_COUNT(cells, counts.locals.cells, total);
|
||||
SET_COUNT(cells, counts.locals.cells, numargs);
|
||||
SET_COUNT(cells, counts.locals.cells, numothers);
|
||||
|
||||
// locals.hidden
|
||||
hidden = PyDict_New();
|
||||
if (hidden == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItemString(locals, "hidden", hidden) < 0) {
|
||||
goto error;
|
||||
}
|
||||
SET_COUNT(hidden, counts.locals.hidden, total);
|
||||
SET_COUNT(hidden, counts.locals.hidden, numpure);
|
||||
SET_COUNT(hidden, counts.locals.hidden, numcells);
|
||||
|
||||
// numfree
|
||||
SET_COUNT(countsobj, counts, numfree);
|
||||
|
||||
// unbound
|
||||
unbound = PyDict_New();
|
||||
if (unbound == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItemString(countsobj, "unbound", unbound) < 0) {
|
||||
goto error;
|
||||
}
|
||||
SET_COUNT(unbound, counts.unbound, total);
|
||||
SET_COUNT(unbound, counts.unbound, numattrs);
|
||||
SET_COUNT(unbound, counts.unbound, numunknown);
|
||||
|
||||
// unbound.globals
|
||||
globals = PyDict_New();
|
||||
if (globals == NULL) {
|
||||
goto error;
|
||||
}
|
||||
if (PyDict_SetItemString(unbound, "globals", globals) < 0) {
|
||||
goto error;
|
||||
}
|
||||
SET_COUNT(globals, counts.unbound.globals, total);
|
||||
SET_COUNT(globals, counts.unbound.globals, numglobal);
|
||||
SET_COUNT(globals, counts.unbound.globals, numbuiltin);
|
||||
SET_COUNT(globals, counts.unbound.globals, numunknown);
|
||||
|
||||
#undef SET_COUNT
|
||||
|
||||
Py_DECREF(locals);
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(cells);
|
||||
Py_DECREF(hidden);
|
||||
Py_DECREF(unbound);
|
||||
Py_DECREF(globals);
|
||||
return countsobj;
|
||||
|
||||
error:
|
||||
Py_DECREF(countsobj);
|
||||
Py_XDECREF(locals);
|
||||
Py_XDECREF(args);
|
||||
Py_XDECREF(cells);
|
||||
Py_XDECREF(hidden);
|
||||
Py_XDECREF(unbound);
|
||||
Py_XDECREF(globals);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
jit_enabled(PyObject *self, PyObject *arg)
|
||||
{
|
||||
|
@ -2120,6 +2286,8 @@ static PyMethodDef module_functions[] = {
|
|||
{"code_returns_only_none", code_returns_only_none, METH_O, NULL},
|
||||
{"get_co_framesize", get_co_framesize, METH_O, NULL},
|
||||
{"get_co_localskinds", get_co_localskinds, METH_O, NULL},
|
||||
{"get_code_var_counts", _PyCFunction_CAST(get_code_var_counts),
|
||||
METH_VARARGS | METH_KEYWORDS, NULL},
|
||||
{"jit_enabled", jit_enabled, METH_NOARGS, NULL},
|
||||
#ifdef _Py_TIER2
|
||||
{"add_executor_dependency", add_executor_dependency, METH_VARARGS, NULL},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue