2016-09-07 15:28:35 -03:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
2005-10-20 16:59:25 -03:00
|
|
|
#include "Python.h"
|
|
|
|
#include "code.h"
|
2019-06-03 09:30:58 -03:00
|
|
|
#include "opcode.h"
|
2020-04-14 21:35:41 -03:00
|
|
|
#include "structmember.h" // PyMemberDef
|
2021-07-16 12:49:35 -03:00
|
|
|
#include "pycore_code.h" // _PyCodeConstructor
|
2020-04-14 09:26:24 -03:00
|
|
|
#include "pycore_interp.h" // PyInterpreterState.co_extra_freefuncs
|
2020-04-14 10:14:01 -03:00
|
|
|
#include "pycore_pystate.h" // _PyInterpreterState_GET()
|
2020-06-22 12:27:35 -03:00
|
|
|
#include "pycore_tuple.h" // _PyTuple_ITEMS()
|
2019-05-24 18:57:23 -03:00
|
|
|
#include "clinic/codeobject.c.h"
|
2005-10-20 16:59:25 -03:00
|
|
|
|
2016-09-07 18:30:39 -03:00
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
/******************
|
|
|
|
* generic helpers
|
|
|
|
******************/
|
2019-05-24 18:57:23 -03:00
|
|
|
|
2017-09-08 03:35:53 -03:00
|
|
|
/* all_name_chars(s): true iff s matches [a-zA-Z0-9_]* */
|
2005-10-20 16:59:25 -03:00
|
|
|
static int
|
2011-09-28 02:41:54 -03:00
|
|
|
all_name_chars(PyObject *o)
|
2005-10-20 16:59:25 -03:00
|
|
|
{
|
2016-10-04 12:17:22 -03:00
|
|
|
const unsigned char *s, *e;
|
2011-09-28 02:41:54 -03:00
|
|
|
|
2017-09-08 03:58:51 -03:00
|
|
|
if (!PyUnicode_IS_ASCII(o))
|
2011-09-28 02:41:54 -03:00
|
|
|
return 0;
|
2010-05-09 12:52:27 -03:00
|
|
|
|
2016-10-04 12:17:22 -03:00
|
|
|
s = PyUnicode_1BYTE_DATA(o);
|
|
|
|
e = s + PyUnicode_GET_LENGTH(o);
|
2017-09-07 22:06:23 -03:00
|
|
|
for (; s != e; s++) {
|
2017-09-08 14:35:49 -03:00
|
|
|
if (!Py_ISALNUM(*s) && *s != '_')
|
2010-05-09 12:52:27 -03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
2005-10-20 16:59:25 -03:00
|
|
|
}
|
|
|
|
|
2020-01-27 18:24:13 -04:00
|
|
|
static int
|
2005-10-20 16:59:25 -03:00
|
|
|
intern_strings(PyObject *tuple)
|
|
|
|
{
|
2010-05-09 12:52:27 -03:00
|
|
|
Py_ssize_t i;
|
|
|
|
|
|
|
|
for (i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
|
|
|
|
PyObject *v = PyTuple_GET_ITEM(tuple, i);
|
|
|
|
if (v == NULL || !PyUnicode_CheckExact(v)) {
|
2020-01-27 18:24:13 -04:00
|
|
|
PyErr_SetString(PyExc_SystemError,
|
|
|
|
"non-string found in code slot");
|
|
|
|
return -1;
|
2010-05-09 12:52:27 -03:00
|
|
|
}
|
2018-11-09 11:56:48 -04:00
|
|
|
PyUnicode_InternInPlace(&_PyTuple_ITEMS(tuple)[i]);
|
2010-05-09 12:52:27 -03:00
|
|
|
}
|
2020-01-27 18:24:13 -04:00
|
|
|
return 0;
|
2005-10-20 16:59:25 -03:00
|
|
|
}
|
|
|
|
|
2016-09-30 04:07:26 -03:00
|
|
|
/* Intern selected string constants */
|
|
|
|
static int
|
2020-01-27 18:24:13 -04:00
|
|
|
intern_string_constants(PyObject *tuple, int *modified)
|
2016-09-30 04:07:26 -03:00
|
|
|
{
|
2020-01-27 18:24:13 -04:00
|
|
|
for (Py_ssize_t i = PyTuple_GET_SIZE(tuple); --i >= 0; ) {
|
2016-09-30 04:07:26 -03:00
|
|
|
PyObject *v = PyTuple_GET_ITEM(tuple, i);
|
|
|
|
if (PyUnicode_CheckExact(v)) {
|
2017-09-08 03:58:51 -03:00
|
|
|
if (PyUnicode_READY(v) == -1) {
|
2020-01-27 18:24:13 -04:00
|
|
|
return -1;
|
2017-09-08 03:58:51 -03:00
|
|
|
}
|
2020-01-27 18:24:13 -04:00
|
|
|
|
2016-09-30 04:07:26 -03:00
|
|
|
if (all_name_chars(v)) {
|
|
|
|
PyObject *w = v;
|
|
|
|
PyUnicode_InternInPlace(&v);
|
|
|
|
if (w != v) {
|
|
|
|
PyTuple_SET_ITEM(tuple, i, v);
|
2020-01-27 18:24:13 -04:00
|
|
|
if (modified) {
|
|
|
|
*modified = 1;
|
|
|
|
}
|
2016-09-30 04:07:26 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (PyTuple_CheckExact(v)) {
|
2020-01-27 18:24:13 -04:00
|
|
|
if (intern_string_constants(v, NULL) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
2016-09-30 04:07:26 -03:00
|
|
|
}
|
|
|
|
else if (PyFrozenSet_CheckExact(v)) {
|
2016-11-09 10:42:14 -04:00
|
|
|
PyObject *w = v;
|
2016-09-30 04:07:26 -03:00
|
|
|
PyObject *tmp = PySequence_Tuple(v);
|
|
|
|
if (tmp == NULL) {
|
2020-01-27 18:24:13 -04:00
|
|
|
return -1;
|
2016-09-30 04:07:26 -03:00
|
|
|
}
|
2020-01-27 18:24:13 -04:00
|
|
|
int tmp_modified = 0;
|
|
|
|
if (intern_string_constants(tmp, &tmp_modified) < 0) {
|
|
|
|
Py_DECREF(tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (tmp_modified) {
|
2016-09-30 04:07:26 -03:00
|
|
|
v = PyFrozenSet_New(tmp);
|
|
|
|
if (v == NULL) {
|
2020-01-27 18:24:13 -04:00
|
|
|
Py_DECREF(tmp);
|
|
|
|
return -1;
|
2016-09-30 04:07:26 -03:00
|
|
|
}
|
2020-01-27 18:24:13 -04:00
|
|
|
|
|
|
|
PyTuple_SET_ITEM(tuple, i, v);
|
|
|
|
Py_DECREF(w);
|
|
|
|
if (modified) {
|
|
|
|
*modified = 1;
|
2016-09-30 04:07:26 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Py_DECREF(tmp);
|
|
|
|
}
|
|
|
|
}
|
2020-01-27 18:24:13 -04:00
|
|
|
return 0;
|
2016-09-30 04:07:26 -03:00
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
/* 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. */
|
|
|
|
static PyObject*
|
|
|
|
validate_and_copy_tuple(PyObject *tup)
|
|
|
|
{
|
|
|
|
PyObject *newtuple;
|
|
|
|
PyObject *item;
|
|
|
|
Py_ssize_t i, len;
|
|
|
|
|
|
|
|
len = PyTuple_GET_SIZE(tup);
|
|
|
|
newtuple = PyTuple_New(len);
|
|
|
|
if (newtuple == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
item = PyTuple_GET_ITEM(tup, i);
|
|
|
|
if (PyUnicode_CheckExact(item)) {
|
|
|
|
Py_INCREF(item);
|
|
|
|
}
|
|
|
|
else if (!PyUnicode_Check(item)) {
|
|
|
|
PyErr_Format(
|
|
|
|
PyExc_TypeError,
|
|
|
|
"name tuples must contain only "
|
|
|
|
"strings, not '%.500s'",
|
|
|
|
Py_TYPE(item)->tp_name);
|
|
|
|
Py_DECREF(newtuple);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
item = _PyUnicode_Copy(item);
|
|
|
|
if (item == NULL) {
|
|
|
|
Py_DECREF(newtuple);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
PyTuple_SET_ITEM(newtuple, i, item);
|
|
|
|
}
|
|
|
|
|
|
|
|
return newtuple;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************
|
2021-05-27 12:54:34 -03:00
|
|
|
* _PyCode_New()
|
2021-05-19 19:44:56 -03:00
|
|
|
******************/
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
// This is also used in compile.c.
|
|
|
|
void
|
2021-06-21 17:53:04 -03:00
|
|
|
_Py_set_localsplus_info(int offset, PyObject *name, _PyLocals_Kind kind,
|
|
|
|
PyObject *names, PyObject *kinds)
|
2021-06-07 15:22:26 -03:00
|
|
|
{
|
|
|
|
Py_INCREF(name);
|
|
|
|
PyTuple_SET_ITEM(names, offset, name);
|
2021-06-21 17:53:04 -03:00
|
|
|
_PyLocals_SetKind(kinds, offset, kind);
|
2021-06-07 15:22:26 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-06-21 17:53:04 -03:00
|
|
|
get_localsplus_counts(PyObject *names, PyObject *kinds,
|
2021-06-15 19:35:25 -03:00
|
|
|
int *pnlocals, int *pnplaincellvars, int *pncellvars,
|
2021-06-07 15:22:26 -03:00
|
|
|
int *pnfreevars)
|
|
|
|
{
|
|
|
|
int nlocals = 0;
|
2021-06-15 19:35:25 -03:00
|
|
|
int nplaincellvars = 0;
|
2021-06-07 15:22:26 -03:00
|
|
|
int ncellvars = 0;
|
|
|
|
int nfreevars = 0;
|
2021-06-15 19:35:25 -03:00
|
|
|
Py_ssize_t nlocalsplus = PyTuple_GET_SIZE(names);
|
2021-06-07 15:22:26 -03:00
|
|
|
for (int i = 0; i < nlocalsplus; i++) {
|
2021-06-21 17:53:04 -03:00
|
|
|
_PyLocals_Kind kind = _PyLocals_GetKind(kinds, i);
|
|
|
|
if (kind & CO_FAST_LOCAL) {
|
2021-06-07 15:22:26 -03:00
|
|
|
nlocals += 1;
|
2021-06-21 17:53:04 -03:00
|
|
|
if (kind & CO_FAST_CELL) {
|
2021-06-15 19:35:25 -03:00
|
|
|
ncellvars += 1;
|
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
}
|
2021-06-21 17:53:04 -03:00
|
|
|
else if (kind & CO_FAST_CELL) {
|
2021-06-07 15:22:26 -03:00
|
|
|
ncellvars += 1;
|
2021-06-15 19:35:25 -03:00
|
|
|
nplaincellvars += 1;
|
2021-06-07 15:22:26 -03:00
|
|
|
}
|
2021-06-21 17:53:04 -03:00
|
|
|
else if (kind & CO_FAST_FREE) {
|
2021-06-07 15:22:26 -03:00
|
|
|
nfreevars += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pnlocals != NULL) {
|
|
|
|
*pnlocals = nlocals;
|
|
|
|
}
|
2021-06-15 19:35:25 -03:00
|
|
|
if (pnplaincellvars != NULL) {
|
|
|
|
*pnplaincellvars = nplaincellvars;
|
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
if (pncellvars != NULL) {
|
|
|
|
*pncellvars = ncellvars;
|
|
|
|
}
|
|
|
|
if (pnfreevars != NULL) {
|
|
|
|
*pnfreevars = nfreevars;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
2021-06-21 17:53:04 -03:00
|
|
|
get_localsplus_names(PyCodeObject *co, _PyLocals_Kind kind, int num)
|
2021-06-07 15:22:26 -03:00
|
|
|
{
|
|
|
|
PyObject *names = PyTuple_New(num);
|
|
|
|
if (names == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
int index = 0;
|
|
|
|
for (int offset = 0; offset < co->co_nlocalsplus; offset++) {
|
2021-06-21 17:53:04 -03:00
|
|
|
_PyLocals_Kind k = _PyLocals_GetKind(co->co_localspluskinds, offset);
|
|
|
|
if ((k & kind) == 0) {
|
2021-06-07 15:22:26 -03:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
assert(index < num);
|
|
|
|
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, offset);
|
|
|
|
Py_INCREF(name);
|
|
|
|
PyTuple_SET_ITEM(names, index, name);
|
|
|
|
index += 1;
|
|
|
|
}
|
|
|
|
assert(index == num);
|
|
|
|
return names;
|
|
|
|
}
|
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
int
|
|
|
|
_PyCode_Validate(struct _PyCodeConstructor *con)
|
2005-10-20 16:59:25 -03:00
|
|
|
{
|
2010-05-09 12:52:27 -03:00
|
|
|
/* Check argument types */
|
2021-05-27 12:54:34 -03:00
|
|
|
if (con->argcount < con->posonlyargcount || con->posonlyargcount < 0 ||
|
|
|
|
con->kwonlyargcount < 0 ||
|
|
|
|
con->stacksize < 0 || con->flags < 0 ||
|
|
|
|
con->code == NULL || !PyBytes_Check(con->code) ||
|
|
|
|
con->consts == NULL || !PyTuple_Check(con->consts) ||
|
|
|
|
con->names == NULL || !PyTuple_Check(con->names) ||
|
2021-06-07 15:22:26 -03:00
|
|
|
con->localsplusnames == NULL || !PyTuple_Check(con->localsplusnames) ||
|
2021-06-21 17:53:04 -03:00
|
|
|
con->localspluskinds == NULL || !PyBytes_Check(con->localspluskinds) ||
|
|
|
|
PyTuple_GET_SIZE(con->localsplusnames)
|
|
|
|
!= PyBytes_GET_SIZE(con->localspluskinds) ||
|
2021-05-27 12:54:34 -03:00
|
|
|
con->name == NULL || !PyUnicode_Check(con->name) ||
|
2021-07-07 08:21:51 -03:00
|
|
|
con->qualname == NULL || !PyUnicode_Check(con->qualname) ||
|
2021-05-27 12:54:34 -03:00
|
|
|
con->filename == NULL || !PyUnicode_Check(con->filename) ||
|
|
|
|
con->linetable == NULL || !PyBytes_Check(con->linetable) ||
|
2021-07-02 11:10:11 -03:00
|
|
|
con->endlinetable == NULL ||
|
|
|
|
(con->endlinetable != Py_None && !PyBytes_Check(con->endlinetable)) ||
|
|
|
|
con->columntable == NULL ||
|
|
|
|
(con->columntable != Py_None && !PyBytes_Check(con->columntable)) ||
|
2021-05-27 12:54:34 -03:00
|
|
|
con->exceptiontable == NULL || !PyBytes_Check(con->exceptiontable)
|
|
|
|
) {
|
2010-05-09 12:52:27 -03:00
|
|
|
PyErr_BadInternalCall();
|
2021-05-27 12:54:34 -03:00
|
|
|
return -1;
|
2010-05-09 12:52:27 -03:00
|
|
|
}
|
2013-10-10 10:55:14 -03:00
|
|
|
|
2021-05-26 16:15:40 -03:00
|
|
|
/* Make sure that code is indexable with an int, this is
|
|
|
|
a long running assumption in ceval.c and many parts of
|
|
|
|
the interpreter. */
|
2021-05-27 12:54:34 -03:00
|
|
|
if (PyBytes_GET_SIZE(con->code) > INT_MAX) {
|
2021-06-07 15:22:26 -03:00
|
|
|
PyErr_SetString(PyExc_OverflowError,
|
|
|
|
"code: co_code larger than INT_MAX");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (PyBytes_GET_SIZE(con->code) % sizeof(_Py_CODEUNIT) != 0 ||
|
|
|
|
!_Py_IS_ALIGNED(PyBytes_AS_STRING(con->code), sizeof(_Py_CODEUNIT))
|
|
|
|
) {
|
|
|
|
PyErr_SetString(PyExc_ValueError, "code: co_code is malformed");
|
2021-05-27 12:54:34 -03:00
|
|
|
return -1;
|
2021-05-26 16:15:40 -03:00
|
|
|
}
|
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
/* Ensure that the co_varnames has enough names to cover the arg counts.
|
|
|
|
* Note that totalargs = nlocals - nplainlocals. We check nplainlocals
|
|
|
|
* here to avoid the possibility of overflow (however remote). */
|
2021-06-07 15:22:26 -03:00
|
|
|
int nlocals;
|
|
|
|
get_localsplus_counts(con->localsplusnames, con->localspluskinds,
|
2021-06-15 19:35:25 -03:00
|
|
|
&nlocals, NULL, NULL, NULL);
|
2021-06-07 15:22:26 -03:00
|
|
|
int nplainlocals = nlocals -
|
2021-05-27 12:54:34 -03:00
|
|
|
con->argcount -
|
|
|
|
con->kwonlyargcount -
|
|
|
|
((con->flags & CO_VARARGS) != 0) -
|
|
|
|
((con->flags & CO_VARKEYWORDS) != 0);
|
|
|
|
if (nplainlocals < 0) {
|
2021-06-07 15:22:26 -03:00
|
|
|
PyErr_SetString(PyExc_ValueError, "code: co_varnames is too small");
|
2021-05-27 12:54:34 -03:00
|
|
|
return -1;
|
2021-05-26 16:15:40 -03:00
|
|
|
}
|
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
|
|
|
|
{
|
2021-06-07 15:22:26 -03:00
|
|
|
int nlocalsplus = (int)PyTuple_GET_SIZE(con->localsplusnames);
|
2021-06-15 19:35:25 -03:00
|
|
|
int nlocals, nplaincellvars, ncellvars, nfreevars;
|
2021-06-07 15:22:26 -03:00
|
|
|
get_localsplus_counts(con->localsplusnames, con->localspluskinds,
|
2021-06-15 19:35:25 -03:00
|
|
|
&nlocals, &nplaincellvars, &ncellvars, &nfreevars);
|
2021-06-07 15:22:26 -03:00
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
Py_INCREF(con->filename);
|
|
|
|
co->co_filename = con->filename;
|
|
|
|
Py_INCREF(con->name);
|
|
|
|
co->co_name = con->name;
|
2021-07-07 08:21:51 -03:00
|
|
|
Py_INCREF(con->qualname);
|
|
|
|
co->co_qualname = con->qualname;
|
2021-05-27 12:54:34 -03:00
|
|
|
co->co_flags = con->flags;
|
|
|
|
|
|
|
|
Py_INCREF(con->code);
|
|
|
|
co->co_code = con->code;
|
2021-06-07 14:38:06 -03:00
|
|
|
co->co_firstinstr = (_Py_CODEUNIT *)PyBytes_AS_STRING(con->code);
|
2021-05-27 12:54:34 -03:00
|
|
|
co->co_firstlineno = con->firstlineno;
|
|
|
|
Py_INCREF(con->linetable);
|
|
|
|
co->co_linetable = con->linetable;
|
2021-07-02 11:10:11 -03:00
|
|
|
Py_INCREF(con->endlinetable);
|
|
|
|
co->co_endlinetable = con->endlinetable;
|
|
|
|
Py_INCREF(con->columntable);
|
|
|
|
co->co_columntable = con->columntable;
|
2021-05-27 12:54:34 -03:00
|
|
|
|
|
|
|
Py_INCREF(con->consts);
|
|
|
|
co->co_consts = con->consts;
|
|
|
|
Py_INCREF(con->names);
|
|
|
|
co->co_names = con->names;
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
Py_INCREF(con->localsplusnames);
|
|
|
|
co->co_localsplusnames = con->localsplusnames;
|
2021-06-21 17:53:04 -03:00
|
|
|
Py_INCREF(con->localspluskinds);
|
2021-06-07 15:22:26 -03:00
|
|
|
co->co_localspluskinds = con->localspluskinds;
|
2021-05-27 12:54:34 -03:00
|
|
|
|
|
|
|
co->co_argcount = con->argcount;
|
|
|
|
co->co_posonlyargcount = con->posonlyargcount;
|
|
|
|
co->co_kwonlyargcount = con->kwonlyargcount;
|
|
|
|
|
|
|
|
co->co_stacksize = con->stacksize;
|
|
|
|
|
|
|
|
Py_INCREF(con->exceptiontable);
|
|
|
|
co->co_exceptiontable = con->exceptiontable;
|
|
|
|
|
|
|
|
/* derived values */
|
2021-06-07 15:22:26 -03:00
|
|
|
co->co_nlocalsplus = nlocalsplus;
|
|
|
|
co->co_nlocals = nlocals;
|
2021-06-15 19:35:25 -03:00
|
|
|
co->co_nplaincellvars = nplaincellvars;
|
2021-06-07 15:22:26 -03:00
|
|
|
co->co_ncellvars = ncellvars;
|
|
|
|
co->co_nfreevars = nfreevars;
|
|
|
|
co->co_varnames = NULL;
|
|
|
|
co->co_cellvars = NULL;
|
|
|
|
co->co_freevars = NULL;
|
2021-05-27 12:54:34 -03:00
|
|
|
|
|
|
|
/* not set */
|
|
|
|
co->co_weakreflist = NULL;
|
|
|
|
co->co_extra = NULL;
|
2021-06-14 07:04:09 -03:00
|
|
|
|
2021-06-07 14:38:06 -03:00
|
|
|
co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
|
|
|
|
co->co_quickened = NULL;
|
2021-05-27 12:54:34 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* The caller is responsible for ensuring that the given data is valid. */
|
|
|
|
|
|
|
|
PyCodeObject *
|
|
|
|
_PyCode_New(struct _PyCodeConstructor *con)
|
|
|
|
{
|
2019-05-24 18:57:23 -03:00
|
|
|
/* Ensure that strings are ready Unicode string */
|
2021-05-27 12:54:34 -03:00
|
|
|
if (PyUnicode_READY(con->name) < 0) {
|
2019-05-24 18:57:23 -03:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-07-07 08:21:51 -03:00
|
|
|
if (PyUnicode_READY(con->qualname) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2021-05-27 12:54:34 -03:00
|
|
|
if (PyUnicode_READY(con->filename) < 0) {
|
2013-10-10 10:55:14 -03:00
|
|
|
return NULL;
|
2019-05-24 18:57:23 -03:00
|
|
|
}
|
2013-10-10 10:55:14 -03:00
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
if (intern_strings(con->names) < 0) {
|
2020-01-27 18:24:13 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-05-27 12:54:34 -03:00
|
|
|
if (intern_string_constants(con->consts, NULL) < 0) {
|
2020-01-27 18:24:13 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
if (intern_strings(con->localsplusnames) < 0) {
|
2020-01-27 18:24:13 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
2017-12-02 21:12:20 -04:00
|
|
|
|
2021-07-07 16:07:12 -03:00
|
|
|
// Discard the endlinetable and columntable if we are opted out of debug
|
|
|
|
// ranges.
|
2021-12-02 06:43:37 -04:00
|
|
|
if (!_Py_GetConfig()->code_debug_ranges) {
|
2021-07-07 16:07:12 -03:00
|
|
|
con->endlinetable = Py_None;
|
|
|
|
con->columntable = Py_None;
|
|
|
|
}
|
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
PyCodeObject *co = PyObject_New(PyCodeObject, &PyCode_Type);
|
|
|
|
if (co == NULL) {
|
|
|
|
PyErr_NoMemory();
|
2018-07-16 03:10:19 -03:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-05-27 12:54:34 -03:00
|
|
|
init_code(co, con);
|
2018-07-16 03:10:19 -03:00
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
return co;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************
|
|
|
|
* the legacy "constructors"
|
|
|
|
******************/
|
|
|
|
|
|
|
|
PyCodeObject *
|
|
|
|
PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
|
|
|
|
int nlocals, int stacksize, int flags,
|
|
|
|
PyObject *code, PyObject *consts, PyObject *names,
|
|
|
|
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
|
2021-07-07 08:21:51 -03:00
|
|
|
PyObject *filename, PyObject *name,
|
|
|
|
PyObject *qualname, int firstlineno,
|
2021-07-02 11:10:11 -03:00
|
|
|
PyObject *linetable, PyObject *endlinetable,
|
|
|
|
PyObject *columntable, PyObject *exceptiontable)
|
2021-05-27 12:54:34 -03:00
|
|
|
{
|
2021-06-07 15:22:26 -03:00
|
|
|
PyCodeObject *co = NULL;
|
|
|
|
PyObject *localsplusnames = NULL;
|
2021-06-21 17:53:04 -03:00
|
|
|
PyObject *localspluskinds = NULL;
|
2021-06-07 15:22:26 -03:00
|
|
|
|
|
|
|
if (varnames == NULL || !PyTuple_Check(varnames) ||
|
|
|
|
cellvars == NULL || !PyTuple_Check(cellvars) ||
|
|
|
|
freevars == NULL || !PyTuple_Check(freevars)
|
|
|
|
) {
|
|
|
|
PyErr_BadInternalCall();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the "fast locals plus" info.
|
|
|
|
int nvarnames = (int)PyTuple_GET_SIZE(varnames);
|
|
|
|
int ncellvars = (int)PyTuple_GET_SIZE(cellvars);
|
|
|
|
int nfreevars = (int)PyTuple_GET_SIZE(freevars);
|
|
|
|
int nlocalsplus = nvarnames + ncellvars + nfreevars;
|
|
|
|
localsplusnames = PyTuple_New(nlocalsplus);
|
|
|
|
if (localsplusnames == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
2021-06-21 17:53:04 -03:00
|
|
|
localspluskinds = PyBytes_FromStringAndSize(NULL, nlocalsplus);
|
|
|
|
if (localspluskinds == NULL) {
|
2021-06-07 15:22:26 -03:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
int offset = 0;
|
|
|
|
for (int i = 0; i < nvarnames; i++, offset++) {
|
|
|
|
PyObject *name = PyTuple_GET_ITEM(varnames, i);
|
|
|
|
_Py_set_localsplus_info(offset, name, CO_FAST_LOCAL,
|
|
|
|
localsplusnames, localspluskinds);
|
|
|
|
}
|
|
|
|
for (int i = 0; i < ncellvars; i++, offset++) {
|
|
|
|
PyObject *name = PyTuple_GET_ITEM(cellvars, i);
|
2021-06-15 19:35:25 -03:00
|
|
|
int argoffset = -1;
|
|
|
|
for (int j = 0; j < nvarnames; j++) {
|
|
|
|
int cmp = PyUnicode_Compare(PyTuple_GET_ITEM(varnames, j),
|
|
|
|
name);
|
|
|
|
assert(!PyErr_Occurred());
|
|
|
|
if (cmp == 0) {
|
|
|
|
argoffset = j;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (argoffset >= 0) {
|
|
|
|
// Merge the localsplus indices.
|
|
|
|
nlocalsplus -= 1;
|
|
|
|
offset -= 1;
|
2021-06-21 17:53:04 -03:00
|
|
|
_PyLocals_Kind kind = _PyLocals_GetKind(localspluskinds, argoffset);
|
|
|
|
_PyLocals_SetKind(localspluskinds, argoffset, kind | CO_FAST_CELL);
|
2021-06-15 19:35:25 -03:00
|
|
|
continue;
|
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
_Py_set_localsplus_info(offset, name, CO_FAST_CELL,
|
|
|
|
localsplusnames, localspluskinds);
|
|
|
|
}
|
|
|
|
for (int i = 0; i < nfreevars; i++, offset++) {
|
|
|
|
PyObject *name = PyTuple_GET_ITEM(freevars, i);
|
|
|
|
_Py_set_localsplus_info(offset, name, CO_FAST_FREE,
|
|
|
|
localsplusnames, localspluskinds);
|
|
|
|
}
|
2021-06-15 19:35:25 -03:00
|
|
|
// If any cells were args then nlocalsplus will have shrunk.
|
2021-08-16 15:34:23 -03:00
|
|
|
if (nlocalsplus != PyTuple_GET_SIZE(localsplusnames)) {
|
|
|
|
if (_PyTuple_Resize(&localsplusnames, nlocalsplus) < 0
|
|
|
|
|| _PyBytes_Resize(&localspluskinds, nlocalsplus) < 0) {
|
|
|
|
goto error;
|
|
|
|
}
|
2021-06-15 19:35:25 -03:00
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
struct _PyCodeConstructor con = {
|
|
|
|
.filename = filename,
|
|
|
|
.name = name,
|
2021-07-07 08:21:51 -03:00
|
|
|
.qualname = qualname,
|
2021-05-27 12:54:34 -03:00
|
|
|
.flags = flags,
|
|
|
|
|
|
|
|
.code = code,
|
|
|
|
.firstlineno = firstlineno,
|
|
|
|
.linetable = linetable,
|
2021-07-02 11:10:11 -03:00
|
|
|
.endlinetable = endlinetable,
|
|
|
|
.columntable = columntable,
|
2021-05-27 12:54:34 -03:00
|
|
|
|
|
|
|
.consts = consts,
|
|
|
|
.names = names,
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
.localsplusnames = localsplusnames,
|
|
|
|
.localspluskinds = localspluskinds,
|
2021-05-27 12:54:34 -03:00
|
|
|
|
|
|
|
.argcount = argcount,
|
|
|
|
.posonlyargcount = posonlyargcount,
|
|
|
|
.kwonlyargcount = kwonlyargcount,
|
|
|
|
|
|
|
|
.stacksize = stacksize,
|
|
|
|
|
|
|
|
.exceptiontable = exceptiontable,
|
|
|
|
};
|
2021-06-07 15:22:26 -03:00
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
if (_PyCode_Validate(&con) < 0) {
|
2021-06-07 15:22:26 -03:00
|
|
|
goto error;
|
2010-05-09 12:52:27 -03:00
|
|
|
}
|
2021-06-07 14:38:06 -03:00
|
|
|
assert(PyBytes_GET_SIZE(code) % sizeof(_Py_CODEUNIT) == 0);
|
|
|
|
assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(code), sizeof(_Py_CODEUNIT)));
|
2021-05-27 12:54:34 -03:00
|
|
|
if (nlocals != PyTuple_GET_SIZE(varnames)) {
|
|
|
|
PyErr_SetString(PyExc_ValueError,
|
|
|
|
"code: co_nlocals != len(co_varnames)");
|
2021-06-07 15:22:26 -03:00
|
|
|
goto error;
|
2021-05-27 12:54:34 -03:00
|
|
|
}
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
co = _PyCode_New(&con);
|
|
|
|
if (co == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
Py_INCREF(varnames);
|
|
|
|
co->co_varnames = varnames;
|
|
|
|
Py_INCREF(cellvars);
|
|
|
|
co->co_cellvars = cellvars;
|
|
|
|
Py_INCREF(freevars);
|
|
|
|
co->co_freevars = freevars;
|
|
|
|
|
|
|
|
error:
|
|
|
|
Py_XDECREF(localsplusnames);
|
2021-06-21 17:53:04 -03:00
|
|
|
Py_XDECREF(localspluskinds);
|
2021-06-07 15:22:26 -03:00
|
|
|
return co;
|
2005-10-20 16:59:25 -03:00
|
|
|
}
|
|
|
|
|
2019-07-01 07:35:05 -03:00
|
|
|
PyCodeObject *
|
|
|
|
PyCode_New(int argcount, int kwonlyargcount,
|
|
|
|
int nlocals, int stacksize, int flags,
|
|
|
|
PyObject *code, PyObject *consts, PyObject *names,
|
|
|
|
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
|
2021-07-07 08:21:51 -03:00
|
|
|
PyObject *filename, PyObject *name, PyObject *qualname,
|
|
|
|
int firstlineno, PyObject *linetable, PyObject *endlinetable,
|
2021-07-02 11:10:11 -03:00
|
|
|
PyObject *columntable, PyObject *exceptiontable)
|
2019-07-01 07:35:05 -03:00
|
|
|
{
|
|
|
|
return PyCode_NewWithPosOnlyArgs(argcount, 0, kwonlyargcount, nlocals,
|
|
|
|
stacksize, flags, code, consts, names,
|
|
|
|
varnames, freevars, cellvars, filename,
|
2021-07-07 08:21:51 -03:00
|
|
|
name, qualname, firstlineno, linetable,
|
|
|
|
endlinetable, columntable, exceptiontable);
|
2019-07-01 07:35:05 -03:00
|
|
|
}
|
|
|
|
|
Merged revisions 72487-72488,72879 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r72487 | jeffrey.yasskin | 2009-05-08 17:51:06 -0400 (Fri, 08 May 2009) | 7 lines
PyCode_NewEmpty:
Most uses of PyCode_New found by http://www.google.com/codesearch?q=PyCode_New
are trying to build an empty code object, usually to put it in a dummy frame
object. This patch adds a PyCode_NewEmpty wrapper which lets the user specify
just the filename, function name, and first line number, instead of also
requiring lots of code internals.
........
r72488 | jeffrey.yasskin | 2009-05-08 18:23:21 -0400 (Fri, 08 May 2009) | 13 lines
Issue 5954, PyFrame_GetLineNumber:
Most uses of PyCode_Addr2Line
(http://www.google.com/codesearch?q=PyCode_Addr2Line) are just trying to get
the line number of a specified frame, but there's no way to do that directly.
Forcing people to go through the code object makes them know more about the
guts of the interpreter than they should need.
The remaining uses of PyCode_Addr2Line seem to be getting the line from a
traceback (for example,
http://www.google.com/codesearch/p?hl=en#u_9_nDrchrw/pygame-1.7.1release/src/base.c&q=PyCode_Addr2Line),
which is replaced by the tb_lineno field. So we may be able to deprecate
PyCode_Addr2Line entirely for external use.
........
r72879 | jeffrey.yasskin | 2009-05-23 19:23:01 -0400 (Sat, 23 May 2009) | 14 lines
Issue #6042:
lnotab-based tracing is very complicated and isn't documented very well. There
were at least 3 comment blocks purporting to document co_lnotab, and none did a
very good job. This patch unifies them into Objects/lnotab_notes.txt which
tries to completely capture the current state of affairs.
I also discovered that we've attached 2 layers of patches to the basic tracing
scheme. The first layer avoids jumping to instructions that don't start a line,
to avoid problems in if statements and while loops. The second layer
discovered that jumps backward do need to trace at instructions that don't
start a line, so it added extra lnotab entries for 'while' and 'for' loops, and
added a special case for backward jumps within the same line. I replaced these
patches by just treating forward and backward jumps differently.
........
2009-07-21 01:30:03 -03:00
|
|
|
PyCodeObject *
|
|
|
|
PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
|
|
|
|
{
|
2021-05-27 12:54:34 -03:00
|
|
|
PyObject *emptystring = NULL;
|
|
|
|
PyObject *nulltuple = NULL;
|
2010-05-09 12:52:27 -03:00
|
|
|
PyObject *filename_ob = NULL;
|
|
|
|
PyObject *funcname_ob = NULL;
|
|
|
|
PyCodeObject *result = NULL;
|
2021-05-27 12:54:34 -03:00
|
|
|
|
|
|
|
emptystring = PyBytes_FromString("");
|
2010-05-09 12:52:27 -03:00
|
|
|
if (emptystring == NULL) {
|
2021-05-27 12:54:34 -03:00
|
|
|
goto failed;
|
2010-05-09 12:52:27 -03:00
|
|
|
}
|
2021-05-27 12:54:34 -03:00
|
|
|
nulltuple = PyTuple_New(0);
|
2010-05-09 12:52:27 -03:00
|
|
|
if (nulltuple == NULL) {
|
2021-05-27 12:54:34 -03:00
|
|
|
goto failed;
|
2010-05-09 12:52:27 -03:00
|
|
|
}
|
|
|
|
funcname_ob = PyUnicode_FromString(funcname);
|
2021-05-27 12:54:34 -03:00
|
|
|
if (funcname_ob == NULL) {
|
2010-05-09 12:52:27 -03:00
|
|
|
goto failed;
|
2021-05-27 12:54:34 -03:00
|
|
|
}
|
2010-05-09 12:52:27 -03:00
|
|
|
filename_ob = PyUnicode_DecodeFSDefault(filename);
|
2021-05-27 12:54:34 -03:00
|
|
|
if (filename_ob == NULL) {
|
2010-05-09 12:52:27 -03:00
|
|
|
goto failed;
|
2021-05-27 12:54:34 -03:00
|
|
|
}
|
2010-05-09 12:52:27 -03:00
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
struct _PyCodeConstructor con = {
|
|
|
|
.filename = filename_ob,
|
|
|
|
.name = funcname_ob,
|
2021-07-07 08:21:51 -03:00
|
|
|
.qualname = funcname_ob,
|
2021-05-27 12:54:34 -03:00
|
|
|
.code = emptystring,
|
|
|
|
.firstlineno = firstlineno,
|
|
|
|
.linetable = emptystring,
|
2021-07-02 11:10:11 -03:00
|
|
|
.endlinetable = emptystring,
|
|
|
|
.columntable = emptystring,
|
2021-05-27 12:54:34 -03:00
|
|
|
.consts = nulltuple,
|
|
|
|
.names = nulltuple,
|
2021-06-07 15:22:26 -03:00
|
|
|
.localsplusnames = nulltuple,
|
2021-06-21 17:53:04 -03:00
|
|
|
.localspluskinds = emptystring,
|
2021-05-27 12:54:34 -03:00
|
|
|
.exceptiontable = emptystring,
|
|
|
|
};
|
|
|
|
result = _PyCode_New(&con);
|
Merged revisions 72487-72488,72879 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r72487 | jeffrey.yasskin | 2009-05-08 17:51:06 -0400 (Fri, 08 May 2009) | 7 lines
PyCode_NewEmpty:
Most uses of PyCode_New found by http://www.google.com/codesearch?q=PyCode_New
are trying to build an empty code object, usually to put it in a dummy frame
object. This patch adds a PyCode_NewEmpty wrapper which lets the user specify
just the filename, function name, and first line number, instead of also
requiring lots of code internals.
........
r72488 | jeffrey.yasskin | 2009-05-08 18:23:21 -0400 (Fri, 08 May 2009) | 13 lines
Issue 5954, PyFrame_GetLineNumber:
Most uses of PyCode_Addr2Line
(http://www.google.com/codesearch?q=PyCode_Addr2Line) are just trying to get
the line number of a specified frame, but there's no way to do that directly.
Forcing people to go through the code object makes them know more about the
guts of the interpreter than they should need.
The remaining uses of PyCode_Addr2Line seem to be getting the line from a
traceback (for example,
http://www.google.com/codesearch/p?hl=en#u_9_nDrchrw/pygame-1.7.1release/src/base.c&q=PyCode_Addr2Line),
which is replaced by the tb_lineno field. So we may be able to deprecate
PyCode_Addr2Line entirely for external use.
........
r72879 | jeffrey.yasskin | 2009-05-23 19:23:01 -0400 (Sat, 23 May 2009) | 14 lines
Issue #6042:
lnotab-based tracing is very complicated and isn't documented very well. There
were at least 3 comment blocks purporting to document co_lnotab, and none did a
very good job. This patch unifies them into Objects/lnotab_notes.txt which
tries to completely capture the current state of affairs.
I also discovered that we've attached 2 layers of patches to the basic tracing
scheme. The first layer avoids jumping to instructions that don't start a line,
to avoid problems in if statements and while loops. The second layer
discovered that jumps backward do need to trace at instructions that don't
start a line, so it added extra lnotab entries for 'while' and 'for' loops, and
added a special case for backward jumps within the same line. I replaced these
patches by just treating forward and backward jumps differently.
........
2009-07-21 01:30:03 -03:00
|
|
|
|
|
|
|
failed:
|
2021-05-27 12:54:34 -03:00
|
|
|
Py_XDECREF(emptystring);
|
|
|
|
Py_XDECREF(nulltuple);
|
2010-05-09 12:52:27 -03:00
|
|
|
Py_XDECREF(funcname_ob);
|
|
|
|
Py_XDECREF(filename_ob);
|
|
|
|
return result;
|
Merged revisions 72487-72488,72879 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r72487 | jeffrey.yasskin | 2009-05-08 17:51:06 -0400 (Fri, 08 May 2009) | 7 lines
PyCode_NewEmpty:
Most uses of PyCode_New found by http://www.google.com/codesearch?q=PyCode_New
are trying to build an empty code object, usually to put it in a dummy frame
object. This patch adds a PyCode_NewEmpty wrapper which lets the user specify
just the filename, function name, and first line number, instead of also
requiring lots of code internals.
........
r72488 | jeffrey.yasskin | 2009-05-08 18:23:21 -0400 (Fri, 08 May 2009) | 13 lines
Issue 5954, PyFrame_GetLineNumber:
Most uses of PyCode_Addr2Line
(http://www.google.com/codesearch?q=PyCode_Addr2Line) are just trying to get
the line number of a specified frame, but there's no way to do that directly.
Forcing people to go through the code object makes them know more about the
guts of the interpreter than they should need.
The remaining uses of PyCode_Addr2Line seem to be getting the line from a
traceback (for example,
http://www.google.com/codesearch/p?hl=en#u_9_nDrchrw/pygame-1.7.1release/src/base.c&q=PyCode_Addr2Line),
which is replaced by the tb_lineno field. So we may be able to deprecate
PyCode_Addr2Line entirely for external use.
........
r72879 | jeffrey.yasskin | 2009-05-23 19:23:01 -0400 (Sat, 23 May 2009) | 14 lines
Issue #6042:
lnotab-based tracing is very complicated and isn't documented very well. There
were at least 3 comment blocks purporting to document co_lnotab, and none did a
very good job. This patch unifies them into Objects/lnotab_notes.txt which
tries to completely capture the current state of affairs.
I also discovered that we've attached 2 layers of patches to the basic tracing
scheme. The first layer avoids jumping to instructions that don't start a line,
to avoid problems in if statements and while loops. The second layer
discovered that jumps backward do need to trace at instructions that don't
start a line, so it added extra lnotab entries for 'while' and 'for' loops, and
added a special case for backward jumps within the same line. I replaced these
patches by just treating forward and backward jumps differently.
........
2009-07-21 01:30:03 -03:00
|
|
|
}
|
2005-10-20 16:59:25 -03:00
|
|
|
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
/******************
|
2021-07-02 11:10:11 -03:00
|
|
|
* source location tracking (co_lines/co_positions)
|
2021-05-19 19:44:56 -03:00
|
|
|
******************/
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2021-07-02 11:10:11 -03:00
|
|
|
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) {
|
2021-07-04 15:02:16 -03:00
|
|
|
return -1;
|
2021-07-02 11:10:11 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
assert(addrq >= 0 && addrq < PyBytes_GET_SIZE(co->co_code));
|
|
|
|
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) {
|
2021-07-04 15:02:16 -03:00
|
|
|
return -1;
|
2021-07-02 11:10:11 -03:00
|
|
|
}
|
2021-10-04 08:11:26 -03:00
|
|
|
addrq /= sizeof(_Py_CODEUNIT);
|
|
|
|
if (addrq*2 >= PyBytes_GET_SIZE(co->co_columntable)) {
|
2021-07-04 15:02:16 -03:00
|
|
|
return -1;
|
2021-07-02 11:10:11 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char* bytes = (unsigned char*)PyBytes_AS_STRING(co->co_columntable);
|
2021-10-04 08:11:26 -03:00
|
|
|
return bytes[addrq*2] - 1;
|
2021-07-02 11:10:11 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
_PyCode_Addr2EndOffset(PyCodeObject* co, int addrq)
|
|
|
|
{
|
|
|
|
if (co->co_columntable == Py_None || addrq < 0) {
|
2021-07-04 15:02:16 -03:00
|
|
|
return -1;
|
2021-07-02 11:10:11 -03:00
|
|
|
}
|
2021-10-04 08:11:26 -03:00
|
|
|
addrq /= sizeof(_Py_CODEUNIT);
|
|
|
|
if (addrq*2+1 >= PyBytes_GET_SIZE(co->co_columntable)) {
|
2021-07-04 15:02:16 -03:00
|
|
|
return -1;
|
2021-07-02 11:10:11 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char* bytes = (unsigned char*)PyBytes_AS_STRING(co->co_columntable);
|
2021-10-04 08:11:26 -03:00
|
|
|
return bytes[addrq*2+1] - 1;
|
2021-07-02 11:10:11 -03:00
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
void
|
2021-06-12 10:11:59 -03:00
|
|
|
PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int firstlineno, PyCodeAddressRange *range)
|
2021-05-19 19:44:56 -03:00
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2021-06-12 10:11:59 -03:00
|
|
|
const char *linetable = PyBytes_AS_STRING(co->co_linetable);
|
2021-05-19 19:44:56 -03:00
|
|
|
Py_ssize_t length = PyBytes_GET_SIZE(co->co_linetable);
|
|
|
|
PyLineTable_InitAddressRange(linetable, length, co->co_firstlineno, bounds);
|
|
|
|
return bounds->ar_line;
|
|
|
|
}
|
|
|
|
|
2021-07-02 11:10:11 -03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
/* 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
|
|
|
|
_PyCode_CheckLineNumber(int lasti, PyCodeAddressRange *bounds)
|
|
|
|
{
|
|
|
|
while (bounds->ar_end <= lasti) {
|
|
|
|
if (!PyLineTable_NextAddressRange(bounds)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (bounds->ar_start > lasti) {
|
|
|
|
if (!PyLineTable_PreviousAddressRange(bounds)) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bounds->ar_line;
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
|
|
|
assert(!at_end(range));
|
|
|
|
advance(range);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
2005-10-20 16:59:25 -03:00
|
|
|
|
2020-11-12 05:43:29 -04:00
|
|
|
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;
|
|
|
|
}
|
2021-01-30 09:54:22 -04:00
|
|
|
unsigned char *lnotab = (unsigned char *) PyBytes_AS_STRING(*bytes);
|
|
|
|
lnotab += *offset;
|
2020-11-12 05:43:29 -04:00
|
|
|
*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 *
|
2021-05-19 19:44:56 -03:00
|
|
|
decode_linetable(PyCodeObject *code)
|
2020-11-12 05:43:29 -04:00
|
|
|
{
|
|
|
|
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)) {
|
2021-04-29 09:12:51 -03:00
|
|
|
if (bounds.opaque.computed_line != line) {
|
2020-11-12 05:43:29 -04:00
|
|
|
int bdelta = bounds.ar_start - code_offset;
|
2021-04-29 09:12:51 -03:00
|
|
|
int ldelta = bounds.opaque.computed_line - line;
|
2020-11-12 05:43:29 -04:00
|
|
|
if (!emit_delta(&bytes, bdelta, ldelta, &table_offset)) {
|
|
|
|
Py_DECREF(bytes);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
code_offset = bounds.ar_start;
|
2021-04-29 09:12:51 -03:00
|
|
|
line = bounds.opaque.computed_line;
|
2020-11-12 05:43:29 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_PyBytes_Resize(&bytes, table_offset);
|
|
|
|
return bytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD
|
|
|
|
PyCodeObject *li_code;
|
|
|
|
PyCodeAddressRange li_line;
|
|
|
|
char *li_end;
|
|
|
|
} lineiterator;
|
2020-11-12 05:43:29 -04:00
|
|
|
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
static void
|
|
|
|
lineiter_dealloc(lineiterator *li)
|
|
|
|
{
|
|
|
|
Py_DECREF(li->li_code);
|
|
|
|
Py_TYPE(li)->tp_free(li);
|
|
|
|
}
|
2010-05-09 12:52:27 -03:00
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
static PyObject *
|
|
|
|
lineiter_next(lineiterator *li)
|
|
|
|
{
|
|
|
|
PyCodeAddressRange *bounds = &li->li_line;
|
|
|
|
if (!PyLineTable_NextAddressRange(bounds)) {
|
2010-05-09 12:52:27 -03:00
|
|
|
return NULL;
|
2021-05-19 19:44:56 -03:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
2010-05-09 12:52:27 -03:00
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
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 lineiterator *
|
|
|
|
new_linesiterator(PyCodeObject *code)
|
|
|
|
{
|
|
|
|
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 li;
|
|
|
|
}
|
|
|
|
|
2021-07-02 11:10:11 -03:00
|
|
|
/* co_positions iterator object. */
|
|
|
|
typedef struct {
|
|
|
|
PyObject_HEAD
|
|
|
|
PyCodeObject* pi_code;
|
|
|
|
int pi_offset;
|
|
|
|
} positionsiterator;
|
|
|
|
|
|
|
|
static void
|
|
|
|
positionsiter_dealloc(positionsiterator* pi)
|
|
|
|
{
|
|
|
|
Py_DECREF(pi->pi_code);
|
|
|
|
Py_TYPE(pi)->tp_free(pi);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject*
|
|
|
|
_source_offset_converter(int* value) {
|
2021-07-04 15:02:16 -03:00
|
|
|
if (*value == -1) {
|
2021-07-02 11:10:11 -03:00
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
return PyLong_FromLong(*value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject*
|
|
|
|
positionsiter_next(positionsiterator* pi)
|
|
|
|
{
|
|
|
|
if (pi->pi_offset >= PyBytes_GET_SIZE(pi->pi_code->co_code)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyTypeObject PositionsIterator = {
|
|
|
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
|
|
|
"poisitions_iterator", /* tp_name */
|
|
|
|
sizeof(positionsiterator), /* tp_basicsize */
|
|
|
|
0, /* tp_itemsize */
|
|
|
|
/* methods */
|
|
|
|
(destructor)positionsiter_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)positionsiter_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_positionsiterator(PyCodeObject* code, PyObject* Py_UNUSED(args))
|
|
|
|
{
|
|
|
|
positionsiterator* pi = (positionsiterator*)PyType_GenericAlloc(&PositionsIterator, 0);
|
|
|
|
if (pi == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Py_INCREF(code);
|
|
|
|
pi->pi_code = code;
|
|
|
|
pi->pi_offset = 0;
|
|
|
|
return (PyObject*)pi;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
/******************
|
|
|
|
* "extra" frame eval info (see PEP 523)
|
|
|
|
******************/
|
|
|
|
|
|
|
|
/* Holder for co_extra information */
|
|
|
|
typedef struct {
|
|
|
|
Py_ssize_t ce_size;
|
|
|
|
void *ce_extras[1];
|
|
|
|
} _PyCodeObjectExtra;
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
_PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
|
|
|
|
{
|
|
|
|
if (!PyCode_Check(code)) {
|
|
|
|
PyErr_BadInternalCall();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyCodeObject *o = (PyCodeObject*) code;
|
|
|
|
_PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) o->co_extra;
|
|
|
|
|
|
|
|
if (co_extra == NULL || co_extra->ce_size <= index) {
|
|
|
|
*extra = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*extra = co_extra->ce_extras[index];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
_PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
|
|
|
|
{
|
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
|
|
|
|
|
|
|
if (!PyCode_Check(code) || index < 0 ||
|
|
|
|
index >= interp->co_extra_user_count) {
|
|
|
|
PyErr_BadInternalCall();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyCodeObject *o = (PyCodeObject*) code;
|
|
|
|
_PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra *) o->co_extra;
|
|
|
|
|
|
|
|
if (co_extra == NULL || co_extra->ce_size <= index) {
|
|
|
|
Py_ssize_t i = (co_extra == NULL ? 0 : co_extra->ce_size);
|
|
|
|
co_extra = PyMem_Realloc(
|
|
|
|
co_extra,
|
|
|
|
sizeof(_PyCodeObjectExtra) +
|
|
|
|
(interp->co_extra_user_count-1) * sizeof(void*));
|
|
|
|
if (co_extra == NULL) {
|
|
|
|
return -1;
|
2010-05-09 12:52:27 -03:00
|
|
|
}
|
2021-05-19 19:44:56 -03:00
|
|
|
for (; i < interp->co_extra_user_count; i++) {
|
|
|
|
co_extra->ce_extras[i] = NULL;
|
|
|
|
}
|
|
|
|
co_extra->ce_size = interp->co_extra_user_count;
|
|
|
|
o->co_extra = co_extra;
|
2010-05-09 12:52:27 -03:00
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
if (co_extra->ce_extras[index] != NULL) {
|
|
|
|
freefunc free = interp->co_extra_freefuncs[index];
|
|
|
|
if (free != NULL) {
|
|
|
|
free(co_extra->ce_extras[index]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
co_extra->ce_extras[index] = extra;
|
|
|
|
return 0;
|
2005-10-20 16:59:25 -03:00
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
/******************
|
|
|
|
* other PyCodeObject accessor functions
|
|
|
|
******************/
|
|
|
|
|
|
|
|
PyObject *
|
|
|
|
_PyCode_GetVarnames(PyCodeObject *co)
|
|
|
|
{
|
|
|
|
if (co->co_varnames == NULL) {
|
|
|
|
// PyCodeObject owns this reference.
|
|
|
|
co->co_varnames = get_localsplus_names(co, CO_FAST_LOCAL,
|
|
|
|
co->co_nlocals);
|
|
|
|
if (co->co_varnames == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Py_INCREF(co->co_varnames);
|
|
|
|
return co->co_varnames;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyObject *
|
|
|
|
_PyCode_GetCellvars(PyCodeObject *co)
|
|
|
|
{
|
|
|
|
if (co->co_cellvars == NULL) {
|
|
|
|
// PyCodeObject owns this reference.
|
|
|
|
co->co_cellvars = get_localsplus_names(co, CO_FAST_CELL,
|
|
|
|
co->co_ncellvars);
|
|
|
|
if (co->co_cellvars == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Py_INCREF(co->co_cellvars);
|
|
|
|
return co->co_cellvars;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyObject *
|
|
|
|
_PyCode_GetFreevars(PyCodeObject *co)
|
|
|
|
{
|
|
|
|
if (co->co_freevars == NULL) {
|
|
|
|
// PyCodeObject owns this reference.
|
|
|
|
co->co_freevars = get_localsplus_names(co, CO_FAST_FREE,
|
|
|
|
co->co_nfreevars);
|
|
|
|
if (co->co_freevars == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Py_INCREF(co->co_freevars);
|
|
|
|
return co->co_freevars;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
/******************
|
|
|
|
* PyCode_Type
|
|
|
|
******************/
|
|
|
|
|
|
|
|
/*[clinic input]
|
|
|
|
class code "PyCodeObject *" "&PyCode_Type"
|
|
|
|
[clinic start generated code]*/
|
|
|
|
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=78aa5d576683bb4b]*/
|
|
|
|
|
2020-07-10 04:12:04 -03:00
|
|
|
/*[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
|
2021-07-07 08:21:51 -03:00
|
|
|
qualname: unicode
|
2020-07-10 04:12:04 -03:00
|
|
|
firstlineno: int
|
2020-11-12 05:43:29 -04:00
|
|
|
linetable: object(subclass_of="&PyBytes_Type")
|
2021-07-07 16:07:12 -03:00
|
|
|
endlinetable: object
|
|
|
|
columntable: object
|
2021-05-07 11:19:19 -03:00
|
|
|
exceptiontable: object(subclass_of="&PyBytes_Type")
|
2020-07-10 04:12:04 -03:00
|
|
|
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]*/
|
2005-10-20 16:59:25 -03:00
|
|
|
|
|
|
|
static PyObject *
|
2020-07-10 04:12:04 -03:00
|
|
|
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,
|
2021-07-07 08:21:51 -03:00
|
|
|
PyObject *qualname, int firstlineno, PyObject *linetable,
|
|
|
|
PyObject *endlinetable, PyObject *columntable,
|
|
|
|
PyObject *exceptiontable, PyObject *freevars,
|
|
|
|
PyObject *cellvars)
|
2021-07-07 16:07:12 -03:00
|
|
|
/*[clinic end generated code: output=e1d2086aa8da7c08 input=a06cd92369134063]*/
|
2005-10-20 16:59:25 -03:00
|
|
|
{
|
2010-05-09 12:52:27 -03:00
|
|
|
PyObject *co = NULL;
|
2020-07-10 04:12:04 -03:00
|
|
|
PyObject *ournames = NULL;
|
|
|
|
PyObject *ourvarnames = NULL;
|
|
|
|
PyObject *ourfreevars = NULL;
|
|
|
|
PyObject *ourcellvars = NULL;
|
2010-05-09 12:52:27 -03:00
|
|
|
|
2021-11-26 20:26:45 -04:00
|
|
|
if (PySys_Audit("code.__new__", "OOOiiiiii",
|
|
|
|
code, filename, name, argcount, posonlyargcount,
|
2019-06-01 17:18:48 -03:00
|
|
|
kwonlyargcount, nlocals, stacksize, flags) < 0) {
|
2019-05-23 12:45:22 -03:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-05-09 12:52:27 -03:00
|
|
|
if (argcount < 0) {
|
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_ValueError,
|
|
|
|
"code: argcount must not be negative");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-04-29 09:36:57 -03:00
|
|
|
if (posonlyargcount < 0) {
|
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_ValueError,
|
|
|
|
"code: posonlyargcount must not be negative");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-05-09 12:52:27 -03:00
|
|
|
if (kwonlyargcount < 0) {
|
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_ValueError,
|
|
|
|
"code: kwonlyargcount must not be negative");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (nlocals < 0) {
|
|
|
|
PyErr_SetString(
|
|
|
|
PyExc_ValueError,
|
|
|
|
"code: nlocals must not be negative");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2021-07-07 16:07:12 -03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2010-05-09 12:52:27 -03:00
|
|
|
ournames = validate_and_copy_tuple(names);
|
|
|
|
if (ournames == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
ourvarnames = validate_and_copy_tuple(varnames);
|
|
|
|
if (ourvarnames == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
if (freevars)
|
|
|
|
ourfreevars = validate_and_copy_tuple(freevars);
|
|
|
|
else
|
|
|
|
ourfreevars = PyTuple_New(0);
|
|
|
|
if (ourfreevars == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
if (cellvars)
|
|
|
|
ourcellvars = validate_and_copy_tuple(cellvars);
|
|
|
|
else
|
|
|
|
ourcellvars = PyTuple_New(0);
|
|
|
|
if (ourcellvars == NULL)
|
|
|
|
goto cleanup;
|
|
|
|
|
2019-07-01 07:35:05 -03:00
|
|
|
co = (PyObject *)PyCode_NewWithPosOnlyArgs(argcount, posonlyargcount,
|
|
|
|
kwonlyargcount,
|
|
|
|
nlocals, stacksize, flags,
|
|
|
|
code, consts, ournames,
|
|
|
|
ourvarnames, ourfreevars,
|
|
|
|
ourcellvars, filename,
|
2021-07-07 08:21:51 -03:00
|
|
|
name, qualname, firstlineno,
|
|
|
|
linetable, endlinetable,
|
|
|
|
columntable, exceptiontable
|
2021-05-07 11:19:19 -03:00
|
|
|
);
|
2020-01-27 18:24:13 -04:00
|
|
|
cleanup:
|
2010-05-09 12:52:27 -03:00
|
|
|
Py_XDECREF(ournames);
|
|
|
|
Py_XDECREF(ourvarnames);
|
|
|
|
Py_XDECREF(ourfreevars);
|
|
|
|
Py_XDECREF(ourcellvars);
|
|
|
|
return co;
|
2005-10-20 16:59:25 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
code_dealloc(PyCodeObject *co)
|
|
|
|
{
|
2016-09-07 15:16:41 -03:00
|
|
|
if (co->co_extra != NULL) {
|
2020-04-14 10:14:01 -03:00
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
2016-09-07 18:30:39 -03:00
|
|
|
_PyCodeObjectExtra *co_extra = co->co_extra;
|
2016-09-07 15:16:41 -03:00
|
|
|
|
2016-09-07 18:30:39 -03:00
|
|
|
for (Py_ssize_t i = 0; i < co_extra->ce_size; i++) {
|
2017-06-21 18:44:36 -03:00
|
|
|
freefunc free_extra = interp->co_extra_freefuncs[i];
|
2016-09-07 15:16:41 -03:00
|
|
|
|
|
|
|
if (free_extra != NULL) {
|
2016-09-07 18:30:39 -03:00
|
|
|
free_extra(co_extra->ce_extras[i]);
|
2016-09-07 15:16:41 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-27 21:12:00 -03:00
|
|
|
PyMem_Free(co_extra);
|
2016-09-07 15:16:41 -03:00
|
|
|
}
|
|
|
|
|
2010-05-09 12:52:27 -03:00
|
|
|
Py_XDECREF(co->co_code);
|
|
|
|
Py_XDECREF(co->co_consts);
|
|
|
|
Py_XDECREF(co->co_names);
|
2021-06-07 15:22:26 -03:00
|
|
|
Py_XDECREF(co->co_localsplusnames);
|
2021-06-21 17:53:04 -03:00
|
|
|
Py_XDECREF(co->co_localspluskinds);
|
2010-05-09 12:52:27 -03:00
|
|
|
Py_XDECREF(co->co_varnames);
|
|
|
|
Py_XDECREF(co->co_freevars);
|
|
|
|
Py_XDECREF(co->co_cellvars);
|
|
|
|
Py_XDECREF(co->co_filename);
|
|
|
|
Py_XDECREF(co->co_name);
|
2021-07-07 08:21:51 -03:00
|
|
|
Py_XDECREF(co->co_qualname);
|
2020-11-12 05:43:29 -04:00
|
|
|
Py_XDECREF(co->co_linetable);
|
2021-07-02 11:10:11 -03:00
|
|
|
Py_XDECREF(co->co_endlinetable);
|
|
|
|
Py_XDECREF(co->co_columntable);
|
2021-05-07 11:19:19 -03:00
|
|
|
Py_XDECREF(co->co_exceptiontable);
|
2010-05-09 12:52:27 -03:00
|
|
|
if (co->co_weakreflist != NULL)
|
|
|
|
PyObject_ClearWeakRefs((PyObject*)co);
|
2021-06-07 14:38:06 -03:00
|
|
|
if (co->co_quickened) {
|
|
|
|
PyMem_Free(co->co_quickened);
|
|
|
|
_Py_QuickenedCount--;
|
|
|
|
}
|
2020-12-01 05:37:39 -04:00
|
|
|
PyObject_Free(co);
|
2005-10-20 16:59:25 -03:00
|
|
|
}
|
|
|
|
|
2012-07-26 17:23:23 -03:00
|
|
|
static PyObject *
|
2021-05-19 19:44:56 -03:00
|
|
|
code_repr(PyCodeObject *co)
|
2012-07-26 17:23:23 -03:00
|
|
|
{
|
2021-05-19 19:44:56 -03:00
|
|
|
int lineno;
|
|
|
|
if (co->co_firstlineno != 0)
|
|
|
|
lineno = co->co_firstlineno;
|
|
|
|
else
|
|
|
|
lineno = -1;
|
|
|
|
if (co->co_filename && PyUnicode_Check(co->co_filename)) {
|
|
|
|
return PyUnicode_FromFormat(
|
|
|
|
"<code object %U at %p, file \"%U\", line %d>",
|
|
|
|
co->co_name, co, co->co_filename, lineno);
|
|
|
|
} else {
|
|
|
|
return PyUnicode_FromFormat(
|
|
|
|
"<code object %U at %p, file ???, line %d>",
|
|
|
|
co->co_name, co, lineno);
|
2017-07-04 09:06:16 -03:00
|
|
|
}
|
2021-05-19 19:44:56 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_richcompare(PyObject *self, PyObject *other, int op)
|
|
|
|
{
|
|
|
|
PyCodeObject *co, *cp;
|
|
|
|
int eq;
|
|
|
|
PyObject *consts1, *consts2;
|
|
|
|
PyObject *res;
|
|
|
|
|
|
|
|
if ((op != Py_EQ && op != Py_NE) ||
|
|
|
|
!PyCode_Check(self) ||
|
|
|
|
!PyCode_Check(other)) {
|
|
|
|
Py_RETURN_NOTIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
co = (PyCodeObject *)self;
|
|
|
|
cp = (PyCodeObject *)other;
|
|
|
|
|
|
|
|
eq = PyObject_RichCompareBool(co->co_name, cp->co_name, Py_EQ);
|
|
|
|
if (!eq) goto unequal;
|
|
|
|
eq = co->co_argcount == cp->co_argcount;
|
|
|
|
if (!eq) goto unequal;
|
|
|
|
eq = co->co_posonlyargcount == cp->co_posonlyargcount;
|
|
|
|
if (!eq) goto unequal;
|
|
|
|
eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
|
|
|
|
if (!eq) goto unequal;
|
|
|
|
eq = co->co_flags == cp->co_flags;
|
|
|
|
if (!eq) goto unequal;
|
|
|
|
eq = co->co_firstlineno == cp->co_firstlineno;
|
|
|
|
if (!eq) goto unequal;
|
|
|
|
eq = PyObject_RichCompareBool(co->co_code, cp->co_code, Py_EQ);
|
|
|
|
if (eq <= 0) goto unequal;
|
|
|
|
|
|
|
|
/* compare constants */
|
|
|
|
consts1 = _PyCode_ConstantKey(co->co_consts);
|
|
|
|
if (!consts1)
|
|
|
|
return NULL;
|
|
|
|
consts2 = _PyCode_ConstantKey(cp->co_consts);
|
|
|
|
if (!consts2) {
|
|
|
|
Py_DECREF(consts1);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
eq = PyObject_RichCompareBool(consts1, consts2, Py_EQ);
|
|
|
|
Py_DECREF(consts1);
|
|
|
|
Py_DECREF(consts2);
|
|
|
|
if (eq <= 0) goto unequal;
|
|
|
|
|
|
|
|
eq = PyObject_RichCompareBool(co->co_names, cp->co_names, Py_EQ);
|
|
|
|
if (eq <= 0) goto unequal;
|
2021-06-07 15:22:26 -03:00
|
|
|
eq = PyObject_RichCompareBool(co->co_localsplusnames,
|
|
|
|
cp->co_localsplusnames, Py_EQ);
|
2021-05-19 19:44:56 -03:00
|
|
|
if (eq <= 0) goto unequal;
|
|
|
|
|
|
|
|
if (op == Py_EQ)
|
|
|
|
res = Py_True;
|
|
|
|
else
|
|
|
|
res = Py_False;
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
unequal:
|
|
|
|
if (eq < 0)
|
|
|
|
return NULL;
|
|
|
|
if (op == Py_NE)
|
|
|
|
res = Py_True;
|
|
|
|
else
|
|
|
|
res = Py_False;
|
|
|
|
|
|
|
|
done:
|
|
|
|
Py_INCREF(res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Py_hash_t
|
|
|
|
code_hash(PyCodeObject *co)
|
|
|
|
{
|
2021-06-07 15:22:26 -03:00
|
|
|
Py_hash_t h, h0, h1, h2, h3, h4;
|
2021-05-19 19:44:56 -03:00
|
|
|
h0 = PyObject_Hash(co->co_name);
|
|
|
|
if (h0 == -1) return -1;
|
|
|
|
h1 = PyObject_Hash(co->co_code);
|
|
|
|
if (h1 == -1) return -1;
|
|
|
|
h2 = PyObject_Hash(co->co_consts);
|
|
|
|
if (h2 == -1) return -1;
|
|
|
|
h3 = PyObject_Hash(co->co_names);
|
|
|
|
if (h3 == -1) return -1;
|
2021-06-07 15:22:26 -03:00
|
|
|
h4 = PyObject_Hash(co->co_localsplusnames);
|
2021-05-19 19:44:56 -03:00
|
|
|
if (h4 == -1) return -1;
|
2021-06-07 15:22:26 -03:00
|
|
|
h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^
|
2021-05-19 19:44:56 -03:00
|
|
|
co->co_argcount ^ co->co_posonlyargcount ^ co->co_kwonlyargcount ^
|
2021-06-07 15:22:26 -03:00
|
|
|
co->co_flags;
|
2021-05-19 19:44:56 -03:00
|
|
|
if (h == -1) h = -2;
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define OFF(x) offsetof(PyCodeObject, x)
|
|
|
|
|
|
|
|
static PyMemberDef code_memberlist[] = {
|
|
|
|
{"co_argcount", T_INT, OFF(co_argcount), READONLY},
|
|
|
|
{"co_posonlyargcount", T_INT, OFF(co_posonlyargcount), READONLY},
|
|
|
|
{"co_kwonlyargcount", T_INT, OFF(co_kwonlyargcount), READONLY},
|
|
|
|
{"co_stacksize",T_INT, OFF(co_stacksize), READONLY},
|
|
|
|
{"co_flags", T_INT, OFF(co_flags), READONLY},
|
|
|
|
{"co_code", T_OBJECT, OFF(co_code), READONLY},
|
|
|
|
{"co_consts", T_OBJECT, OFF(co_consts), READONLY},
|
|
|
|
{"co_names", T_OBJECT, OFF(co_names), READONLY},
|
|
|
|
{"co_filename", T_OBJECT, OFF(co_filename), READONLY},
|
|
|
|
{"co_name", T_OBJECT, OFF(co_name), READONLY},
|
2021-07-07 08:21:51 -03:00
|
|
|
{"co_qualname", T_OBJECT, OFF(co_qualname), READONLY},
|
2021-05-19 19:44:56 -03:00
|
|
|
{"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY},
|
|
|
|
{"co_linetable", T_OBJECT, OFF(co_linetable), READONLY},
|
2021-07-02 11:10:11 -03:00
|
|
|
{"co_endlinetable", T_OBJECT, OFF(co_endlinetable), READONLY},
|
|
|
|
{"co_columntable", T_OBJECT, OFF(co_columntable), READONLY},
|
2021-05-19 19:44:56 -03:00
|
|
|
{"co_exceptiontable", T_OBJECT, OFF(co_exceptiontable), READONLY},
|
|
|
|
{NULL} /* Sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_getlnotab(PyCodeObject *code, void *closure)
|
|
|
|
{
|
|
|
|
return decode_linetable(code);
|
|
|
|
}
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
static PyObject *
|
|
|
|
code_getnlocals(PyCodeObject *code, void *closure)
|
|
|
|
{
|
|
|
|
return PyLong_FromLong(code->co_nlocals);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_getvarnames(PyCodeObject *code, void *closure)
|
|
|
|
{
|
|
|
|
return _PyCode_GetVarnames(code);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_getcellvars(PyCodeObject *code, void *closure)
|
|
|
|
{
|
|
|
|
return _PyCode_GetCellvars(code);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_getfreevars(PyCodeObject *code, void *closure)
|
|
|
|
{
|
|
|
|
return _PyCode_GetFreevars(code);
|
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
static PyGetSetDef code_getsetlist[] = {
|
|
|
|
{"co_lnotab", (getter)code_getlnotab, NULL, NULL},
|
2021-06-07 15:22:26 -03:00
|
|
|
// The following old names are kept for backward compatibility.
|
|
|
|
{"co_nlocals", (getter)code_getnlocals, NULL, NULL},
|
|
|
|
{"co_varnames", (getter)code_getvarnames, NULL, NULL},
|
|
|
|
{"co_cellvars", (getter)code_getcellvars, NULL, NULL},
|
|
|
|
{"co_freevars", (getter)code_getfreevars, NULL, NULL},
|
2021-05-19 19:44:56 -03:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_sizeof(PyCodeObject *co, PyObject *Py_UNUSED(args))
|
|
|
|
{
|
|
|
|
Py_ssize_t res = _PyObject_SIZE(Py_TYPE(co));
|
bpo-43693: Add new internal code objects fields: co_fastlocalnames and co_fastlocalkinds. (gh-26388)
A number of places in the code base (notably ceval.c and frameobject.c) rely on mapping variable names to indices in the frame "locals plus" array (AKA fast locals), and thus opargs. Currently the compiler indirectly encodes that information on the code object as the tuples co_varnames, co_cellvars, and co_freevars. At runtime the dependent code must calculate the proper mapping from those, which isn't ideal and impacts performance-sensitive sections. This is something we can easily address in the compiler instead.
This change addresses the situation by replacing internal use of co_varnames, etc. with a single combined tuple of names in locals-plus order, along with a minimal array mapping each to its kind (local vs. cell vs. free). These two new PyCodeObject fields, co_fastlocalnames and co_fastllocalkinds, are not exposed to Python code for now, but co_varnames, etc. are still available with the same values as before (though computed lazily).
Aside from the (mild) performance impact, there are a number of other benefits:
* there's now a clear, direct relationship between locals-plus and variables
* code that relies on the locals-plus-to-name mapping is simpler
* marshaled code objects are smaller and serialize/de-serialize faster
Also note that we can take this approach further by expanding the possible values in co_fastlocalkinds to include specific argument types (e.g. positional-only, kwargs). Doing so would allow further speed-ups in _PyEval_MakeFrameVector(), which is where args get unpacked into the locals-plus array. It would also allow us to shrink marshaled code objects even further.
https://bugs.python.org/issue43693
2021-06-03 13:28:27 -03:00
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
_PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) co->co_extra;
|
2021-06-04 13:51:05 -03:00
|
|
|
if (co_extra != NULL) {
|
|
|
|
res += sizeof(_PyCodeObjectExtra) +
|
|
|
|
(co_extra->ce_size-1) * sizeof(co_extra->ce_extras[0]);
|
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
|
2021-06-14 07:04:09 -03:00
|
|
|
if (co->co_quickened != NULL) {
|
|
|
|
Py_ssize_t count = co->co_quickened[0].entry.zero.cache_count;
|
|
|
|
count += (PyBytes_GET_SIZE(co->co_code)+sizeof(SpecializedCacheEntry)-1)/
|
|
|
|
sizeof(SpecializedCacheEntry);
|
|
|
|
res += count * sizeof(SpecializedCacheEntry);
|
2019-06-03 09:30:58 -03:00
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
|
2012-07-26 17:23:23 -03:00
|
|
|
return PyLong_FromSsize_t(res);
|
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
static PyObject *
|
|
|
|
code_linesiterator(PyCodeObject *code, PyObject *Py_UNUSED(args))
|
|
|
|
{
|
|
|
|
return (PyObject *)new_linesiterator(code);
|
|
|
|
}
|
|
|
|
|
2019-05-24 18:57:23 -03:00
|
|
|
/*[clinic input]
|
|
|
|
code.replace
|
|
|
|
|
|
|
|
*
|
|
|
|
co_argcount: int(c_default="self->co_argcount") = -1
|
|
|
|
co_posonlyargcount: int(c_default="self->co_posonlyargcount") = -1
|
|
|
|
co_kwonlyargcount: int(c_default="self->co_kwonlyargcount") = -1
|
|
|
|
co_nlocals: int(c_default="self->co_nlocals") = -1
|
|
|
|
co_stacksize: int(c_default="self->co_stacksize") = -1
|
|
|
|
co_flags: int(c_default="self->co_flags") = -1
|
|
|
|
co_firstlineno: int(c_default="self->co_firstlineno") = -1
|
|
|
|
co_code: PyBytesObject(c_default="(PyBytesObject *)self->co_code") = None
|
|
|
|
co_consts: object(subclass_of="&PyTuple_Type", c_default="self->co_consts") = None
|
|
|
|
co_names: object(subclass_of="&PyTuple_Type", c_default="self->co_names") = None
|
|
|
|
co_varnames: object(subclass_of="&PyTuple_Type", c_default="self->co_varnames") = None
|
|
|
|
co_freevars: object(subclass_of="&PyTuple_Type", c_default="self->co_freevars") = None
|
|
|
|
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
|
2021-07-07 08:21:51 -03:00
|
|
|
co_qualname: unicode(c_default="self->co_qualname") = None
|
2020-11-12 05:43:29 -04:00
|
|
|
co_linetable: PyBytesObject(c_default="(PyBytesObject *)self->co_linetable") = None
|
2021-07-07 16:07:12 -03:00
|
|
|
co_endlinetable: object(c_default="self->co_endlinetable") = None
|
|
|
|
co_columntable: object(c_default="self->co_columntable") = None
|
2021-05-07 11:19:19 -03:00
|
|
|
co_exceptiontable: PyBytesObject(c_default="(PyBytesObject *)self->co_exceptiontable") = None
|
2019-05-24 18:57:23 -03:00
|
|
|
|
2020-01-01 02:11:16 -04:00
|
|
|
Return a copy of the code object with new values for the specified fields.
|
2019-05-24 18:57:23 -03:00
|
|
|
[clinic start generated code]*/
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_replace_impl(PyCodeObject *self, int co_argcount,
|
|
|
|
int co_posonlyargcount, int co_kwonlyargcount,
|
|
|
|
int co_nlocals, int co_stacksize, int co_flags,
|
|
|
|
int co_firstlineno, PyBytesObject *co_code,
|
|
|
|
PyObject *co_consts, PyObject *co_names,
|
|
|
|
PyObject *co_varnames, PyObject *co_freevars,
|
|
|
|
PyObject *co_cellvars, PyObject *co_filename,
|
2021-07-07 08:21:51 -03:00
|
|
|
PyObject *co_name, PyObject *co_qualname,
|
2021-07-07 16:07:12 -03:00
|
|
|
PyBytesObject *co_linetable, PyObject *co_endlinetable,
|
|
|
|
PyObject *co_columntable, PyBytesObject *co_exceptiontable)
|
|
|
|
/*[clinic end generated code: output=f046bf0be3bab91f input=a63d09f248f00794]*/
|
2019-05-24 18:57:23 -03:00
|
|
|
{
|
|
|
|
#define CHECK_INT_ARG(ARG) \
|
|
|
|
if (ARG < 0) { \
|
|
|
|
PyErr_SetString(PyExc_ValueError, \
|
|
|
|
#ARG " must be a positive integer"); \
|
|
|
|
return NULL; \
|
|
|
|
}
|
|
|
|
|
|
|
|
CHECK_INT_ARG(co_argcount);
|
|
|
|
CHECK_INT_ARG(co_posonlyargcount);
|
|
|
|
CHECK_INT_ARG(co_kwonlyargcount);
|
|
|
|
CHECK_INT_ARG(co_nlocals);
|
|
|
|
CHECK_INT_ARG(co_stacksize);
|
|
|
|
CHECK_INT_ARG(co_flags);
|
|
|
|
CHECK_INT_ARG(co_firstlineno);
|
|
|
|
|
|
|
|
#undef CHECK_INT_ARG
|
|
|
|
|
2021-11-26 20:26:45 -04:00
|
|
|
if (PySys_Audit("code.__new__", "OOOiiiiii",
|
|
|
|
co_code, co_filename, co_name, co_argcount,
|
2019-11-26 20:27:50 -04:00
|
|
|
co_posonlyargcount, co_kwonlyargcount, co_nlocals,
|
|
|
|
co_stacksize, co_flags) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
PyCodeObject *co = NULL;
|
|
|
|
PyObject *varnames = NULL;
|
|
|
|
PyObject *cellvars = NULL;
|
|
|
|
PyObject *freevars = NULL;
|
|
|
|
if (co_varnames == NULL) {
|
|
|
|
varnames = get_localsplus_names(self, CO_FAST_LOCAL, self->co_nlocals);
|
|
|
|
if (varnames == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
co_varnames = varnames;
|
|
|
|
}
|
|
|
|
if (co_cellvars == NULL) {
|
|
|
|
cellvars = get_localsplus_names(self, CO_FAST_CELL, self->co_ncellvars);
|
|
|
|
if (cellvars == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
co_cellvars = cellvars;
|
|
|
|
}
|
|
|
|
if (co_freevars == NULL) {
|
|
|
|
freevars = get_localsplus_names(self, CO_FAST_FREE, self->co_nfreevars);
|
|
|
|
if (freevars == NULL) {
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
co_freevars = freevars;
|
|
|
|
}
|
|
|
|
|
2021-07-07 16:07:12 -03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
co = PyCode_NewWithPosOnlyArgs(
|
2019-05-24 18:57:23 -03:00
|
|
|
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,
|
2021-07-07 08:21:51 -03:00
|
|
|
co_qualname, co_firstlineno, (PyObject*)co_linetable,
|
|
|
|
(PyObject*)co_endlinetable, (PyObject*)co_columntable,
|
|
|
|
(PyObject*)co_exceptiontable);
|
2021-06-07 15:22:26 -03:00
|
|
|
|
|
|
|
error:
|
|
|
|
Py_XDECREF(varnames);
|
|
|
|
Py_XDECREF(cellvars);
|
|
|
|
Py_XDECREF(freevars);
|
|
|
|
return (PyObject *)co;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*[clinic input]
|
|
|
|
code._varname_from_oparg
|
|
|
|
|
|
|
|
oparg: int
|
|
|
|
|
|
|
|
(internal-only) Return the local variable name for the given oparg.
|
|
|
|
|
|
|
|
WARNING: this method is for internal use only and may change or go away.
|
|
|
|
[clinic start generated code]*/
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code__varname_from_oparg_impl(PyCodeObject *self, int oparg)
|
|
|
|
/*[clinic end generated code: output=1fd1130413184206 input=c5fa3ee9bac7d4ca]*/
|
|
|
|
{
|
|
|
|
PyObject *name = PyTuple_GetItem(self->co_localsplusnames, oparg);
|
|
|
|
if (name == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
Py_INCREF(name);
|
|
|
|
return name;
|
2019-05-24 18:57:23 -03:00
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
/* 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},
|
2021-07-02 11:10:11 -03:00
|
|
|
{"co_positions", (PyCFunction)code_positionsiterator, METH_NOARGS},
|
2021-05-19 19:44:56 -03:00
|
|
|
CODE_REPLACE_METHODDEF
|
2021-06-07 15:22:26 -03:00
|
|
|
CODE__VARNAME_FROM_OPARG_METHODDEF
|
2021-05-19 19:44:56 -03:00
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
PyTypeObject PyCode_Type = {
|
|
|
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
|
|
|
"code",
|
|
|
|
sizeof(PyCodeObject),
|
|
|
|
0,
|
|
|
|
(destructor)code_dealloc, /* tp_dealloc */
|
|
|
|
0, /* tp_vectorcall_offset */
|
|
|
|
0, /* tp_getattr */
|
|
|
|
0, /* tp_setattr */
|
|
|
|
0, /* tp_as_async */
|
|
|
|
(reprfunc)code_repr, /* tp_repr */
|
|
|
|
0, /* tp_as_number */
|
|
|
|
0, /* tp_as_sequence */
|
|
|
|
0, /* tp_as_mapping */
|
|
|
|
(hashfunc)code_hash, /* tp_hash */
|
|
|
|
0, /* tp_call */
|
|
|
|
0, /* tp_str */
|
|
|
|
PyObject_GenericGetAttr, /* tp_getattro */
|
|
|
|
0, /* tp_setattro */
|
|
|
|
0, /* tp_as_buffer */
|
|
|
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
|
|
|
code_new__doc__, /* tp_doc */
|
|
|
|
0, /* tp_traverse */
|
|
|
|
0, /* tp_clear */
|
|
|
|
code_richcompare, /* tp_richcompare */
|
|
|
|
offsetof(PyCodeObject, co_weakreflist), /* tp_weaklistoffset */
|
|
|
|
0, /* tp_iter */
|
|
|
|
0, /* tp_iternext */
|
|
|
|
code_methods, /* tp_methods */
|
|
|
|
code_memberlist, /* tp_members */
|
|
|
|
code_getsetlist, /* 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 */
|
|
|
|
code_new, /* tp_new */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/******************
|
|
|
|
* other API
|
|
|
|
******************/
|
2005-10-20 16:59:25 -03:00
|
|
|
|
2016-01-22 07:33:12 -04:00
|
|
|
PyObject*
|
|
|
|
_PyCode_ConstantKey(PyObject *op)
|
|
|
|
{
|
|
|
|
PyObject *key;
|
|
|
|
|
2018-04-19 02:28:04 -03:00
|
|
|
/* Py_None and Py_Ellipsis are singletons. */
|
2016-01-22 07:33:12 -04:00
|
|
|
if (op == Py_None || op == Py_Ellipsis
|
|
|
|
|| PyLong_CheckExact(op)
|
|
|
|
|| PyUnicode_CheckExact(op)
|
|
|
|
/* code_richcompare() uses _PyCode_ConstantKey() internally */
|
2018-04-19 02:28:04 -03:00
|
|
|
|| PyCode_Check(op))
|
|
|
|
{
|
|
|
|
/* Objects of these types are always different from object of other
|
|
|
|
* type and from tuples. */
|
|
|
|
Py_INCREF(op);
|
|
|
|
key = op;
|
|
|
|
}
|
|
|
|
else if (PyBool_Check(op) || PyBytes_CheckExact(op)) {
|
|
|
|
/* Make booleans different from integers 0 and 1.
|
|
|
|
* Avoid BytesWarning from comparing bytes with strings. */
|
2016-01-22 07:33:12 -04:00
|
|
|
key = PyTuple_Pack(2, Py_TYPE(op), op);
|
|
|
|
}
|
|
|
|
else if (PyFloat_CheckExact(op)) {
|
|
|
|
double d = PyFloat_AS_DOUBLE(op);
|
|
|
|
/* all we need is to make the tuple different in either the 0.0
|
|
|
|
* or -0.0 case from all others, just to avoid the "coercion".
|
|
|
|
*/
|
|
|
|
if (d == 0.0 && copysign(1.0, d) < 0.0)
|
|
|
|
key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None);
|
|
|
|
else
|
|
|
|
key = PyTuple_Pack(2, Py_TYPE(op), op);
|
|
|
|
}
|
|
|
|
else if (PyComplex_CheckExact(op)) {
|
|
|
|
Py_complex z;
|
|
|
|
int real_negzero, imag_negzero;
|
|
|
|
/* For the complex case we must make complex(x, 0.)
|
|
|
|
different from complex(x, -0.) and complex(0., y)
|
|
|
|
different from complex(-0., y), for any x and y.
|
|
|
|
All four complex zeros must be distinguished.*/
|
|
|
|
z = PyComplex_AsCComplex(op);
|
|
|
|
real_negzero = z.real == 0.0 && copysign(1.0, z.real) < 0.0;
|
|
|
|
imag_negzero = z.imag == 0.0 && copysign(1.0, z.imag) < 0.0;
|
|
|
|
/* use True, False and None singleton as tags for the real and imag
|
|
|
|
* sign, to make tuples different */
|
|
|
|
if (real_negzero && imag_negzero) {
|
|
|
|
key = PyTuple_Pack(3, Py_TYPE(op), op, Py_True);
|
|
|
|
}
|
|
|
|
else if (imag_negzero) {
|
|
|
|
key = PyTuple_Pack(3, Py_TYPE(op), op, Py_False);
|
|
|
|
}
|
|
|
|
else if (real_negzero) {
|
|
|
|
key = PyTuple_Pack(3, Py_TYPE(op), op, Py_None);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
key = PyTuple_Pack(2, Py_TYPE(op), op);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (PyTuple_CheckExact(op)) {
|
|
|
|
Py_ssize_t i, len;
|
|
|
|
PyObject *tuple;
|
|
|
|
|
|
|
|
len = PyTuple_GET_SIZE(op);
|
|
|
|
tuple = PyTuple_New(len);
|
|
|
|
if (tuple == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i=0; i < len; i++) {
|
|
|
|
PyObject *item, *item_key;
|
|
|
|
|
|
|
|
item = PyTuple_GET_ITEM(op, i);
|
|
|
|
item_key = _PyCode_ConstantKey(item);
|
|
|
|
if (item_key == NULL) {
|
|
|
|
Py_DECREF(tuple);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyTuple_SET_ITEM(tuple, i, item_key);
|
|
|
|
}
|
|
|
|
|
2017-01-24 14:49:26 -04:00
|
|
|
key = PyTuple_Pack(2, tuple, op);
|
2016-01-22 07:33:12 -04:00
|
|
|
Py_DECREF(tuple);
|
|
|
|
}
|
|
|
|
else if (PyFrozenSet_CheckExact(op)) {
|
|
|
|
Py_ssize_t pos = 0;
|
|
|
|
PyObject *item;
|
|
|
|
Py_hash_t hash;
|
|
|
|
Py_ssize_t i, len;
|
|
|
|
PyObject *tuple, *set;
|
|
|
|
|
|
|
|
len = PySet_GET_SIZE(op);
|
|
|
|
tuple = PyTuple_New(len);
|
|
|
|
if (tuple == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (_PySet_NextEntry(op, &pos, &item, &hash)) {
|
|
|
|
PyObject *item_key;
|
|
|
|
|
|
|
|
item_key = _PyCode_ConstantKey(item);
|
|
|
|
if (item_key == NULL) {
|
|
|
|
Py_DECREF(tuple);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(i < len);
|
|
|
|
PyTuple_SET_ITEM(tuple, i, item_key);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
set = PyFrozenSet_New(tuple);
|
|
|
|
Py_DECREF(tuple);
|
|
|
|
if (set == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2017-01-24 14:49:26 -04:00
|
|
|
key = PyTuple_Pack(2, set, op);
|
2016-01-22 07:33:12 -04:00
|
|
|
Py_DECREF(set);
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
else {
|
2016-04-14 23:14:19 -03:00
|
|
|
/* for other types, use the object identifier as a unique identifier
|
2016-01-22 07:33:12 -04:00
|
|
|
* to ensure that they are seen as unequal. */
|
|
|
|
PyObject *obj_id = PyLong_FromVoidPtr(op);
|
|
|
|
if (obj_id == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
2017-01-24 14:49:26 -04:00
|
|
|
key = PyTuple_Pack(2, obj_id, op);
|
2016-01-22 07:33:12 -04:00
|
|
|
Py_DECREF(obj_id);
|
|
|
|
}
|
|
|
|
return key;
|
|
|
|
}
|