2016-09-07 15:28:35 -03:00
|
|
|
#include <stdbool.h>
|
|
|
|
|
2005-10-20 16:59:25 -03:00
|
|
|
#include "Python.h"
|
2019-06-03 09:30:58 -03:00
|
|
|
#include "opcode.h"
|
2023-07-25 10:28:30 -03:00
|
|
|
|
2021-07-16 12:49:35 -03:00
|
|
|
#include "pycore_code.h" // _PyCodeConstructor
|
2022-06-20 08:59:25 -03:00
|
|
|
#include "pycore_frame.h" // FRAME_SPECIALS_SIZE
|
2024-05-06 21:12:39 -03:00
|
|
|
#include "pycore_hashtable.h" // _Py_hashtable_t
|
|
|
|
#include "pycore_initconfig.h" // _PyStatus_OK()
|
2020-04-14 09:26:24 -03:00
|
|
|
#include "pycore_interp.h" // PyInterpreterState.co_extra_freefuncs
|
2024-04-16 13:42:53 -03:00
|
|
|
#include "pycore_object.h" // _PyObject_SetDeferredRefcount
|
2023-08-23 14:39:00 -03:00
|
|
|
#include "pycore_opcode_metadata.h" // _PyOpcode_Deopt, _PyOpcode_Caches
|
2023-11-02 07:18:43 -03:00
|
|
|
#include "pycore_opcode_utils.h" // RESUME_AT_FUNC_START
|
2020-04-14 10:14:01 -03:00
|
|
|
#include "pycore_pystate.h" // _PyInterpreterState_GET()
|
2023-07-22 12:04:34 -03:00
|
|
|
#include "pycore_setobject.h" // _PySet_NextEntry()
|
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
|
|
|
|
2023-03-07 20:10:58 -04:00
|
|
|
static const char *
|
|
|
|
code_event_name(PyCodeEvent event) {
|
|
|
|
switch (event) {
|
|
|
|
#define CASE(op) \
|
|
|
|
case PY_CODE_EVENT_##op: \
|
|
|
|
return "PY_CODE_EVENT_" #op;
|
|
|
|
PY_FOREACH_CODE_EVENT(CASE)
|
|
|
|
#undef CASE
|
|
|
|
}
|
|
|
|
Py_UNREACHABLE();
|
|
|
|
}
|
|
|
|
|
2022-12-02 13:28:27 -04:00
|
|
|
static void
|
|
|
|
notify_code_watchers(PyCodeEvent event, PyCodeObject *co)
|
|
|
|
{
|
2023-03-07 20:10:58 -04:00
|
|
|
assert(Py_REFCNT(co) > 0);
|
2022-12-02 13:28:27 -04:00
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
2022-12-14 15:14:16 -04:00
|
|
|
assert(interp->_initialized);
|
|
|
|
uint8_t bits = interp->active_code_watchers;
|
|
|
|
int i = 0;
|
|
|
|
while (bits) {
|
|
|
|
assert(i < CODE_MAX_WATCHERS);
|
|
|
|
if (bits & 1) {
|
2022-12-02 13:28:27 -04:00
|
|
|
PyCode_WatchCallback cb = interp->code_watchers[i];
|
2022-12-14 15:14:16 -04:00
|
|
|
// callback must be non-null if the watcher bit is set
|
|
|
|
assert(cb != NULL);
|
|
|
|
if (cb(event, co) < 0) {
|
2023-11-02 06:16:34 -03:00
|
|
|
PyErr_FormatUnraisable(
|
|
|
|
"Exception ignored in %s watcher callback for %R",
|
|
|
|
code_event_name(event), co);
|
2022-12-02 13:28:27 -04:00
|
|
|
}
|
|
|
|
}
|
2022-12-14 15:14:16 -04:00
|
|
|
i++;
|
|
|
|
bits >>= 1;
|
2022-12-02 13:28:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
PyCode_AddWatcher(PyCode_WatchCallback callback)
|
|
|
|
{
|
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
|
|
|
assert(interp->_initialized);
|
|
|
|
|
|
|
|
for (int i = 0; i < CODE_MAX_WATCHERS; i++) {
|
|
|
|
if (!interp->code_watchers[i]) {
|
|
|
|
interp->code_watchers[i] = callback;
|
|
|
|
interp->active_code_watchers |= (1 << i);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PyErr_SetString(PyExc_RuntimeError, "no more code watcher IDs available");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
validate_watcher_id(PyInterpreterState *interp, int watcher_id)
|
|
|
|
{
|
|
|
|
if (watcher_id < 0 || watcher_id >= CODE_MAX_WATCHERS) {
|
|
|
|
PyErr_Format(PyExc_ValueError, "Invalid code watcher ID %d", watcher_id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!interp->code_watchers[watcher_id]) {
|
|
|
|
PyErr_Format(PyExc_ValueError, "No code watcher set for ID %d", watcher_id);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
PyCode_ClearWatcher(int watcher_id)
|
|
|
|
{
|
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
|
|
|
assert(interp->_initialized);
|
|
|
|
if (validate_watcher_id(interp, watcher_id) < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
interp->code_watchers[watcher_id] = NULL;
|
|
|
|
interp->active_code_watchers &= ~(1 << watcher_id);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
/******************
|
|
|
|
* generic helpers
|
|
|
|
******************/
|
2019-05-24 18:57:23 -03:00
|
|
|
|
2005-10-20 16:59:25 -03:00
|
|
|
static int
|
2024-05-06 21:12:39 -03:00
|
|
|
should_intern_string(PyObject *o)
|
2005-10-20 16:59:25 -03:00
|
|
|
{
|
2024-05-06 21:12:39 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
// The free-threaded build interns (and immortalizes) all string constants
|
|
|
|
// unless we've disabled immortalizing objects that use deferred reference
|
|
|
|
// counting.
|
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
2024-06-03 17:58:41 -03:00
|
|
|
if (_Py_atomic_load_int(&interp->gc.immortalize) < 0) {
|
2024-05-06 21:12:39 -03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// compute if s matches [a-zA-Z0-9_]
|
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
|
|
|
}
|
|
|
|
|
2024-05-06 21:12:39 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
static PyObject *intern_one_constant(PyObject *op);
|
|
|
|
#endif
|
|
|
|
|
2020-01-27 18:24:13 -04:00
|
|
|
static int
|
2005-10-20 16:59:25 -03:00
|
|
|
intern_strings(PyObject *tuple)
|
|
|
|
{
|
2024-06-21 12:19:31 -03:00
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
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
|
|
|
}
|
2024-07-17 06:31:28 -03:00
|
|
|
_PyUnicode_InternImmortal(interp, &_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
|
|
|
}
|
|
|
|
|
2024-05-06 21:12:39 -03:00
|
|
|
/* Intern constants. In the default build, this interns selected string
|
|
|
|
constants. In the free-threaded build, this also interns non-string
|
|
|
|
constants. */
|
2016-09-30 04:07:26 -03:00
|
|
|
static int
|
2024-05-06 21:12:39 -03:00
|
|
|
intern_constants(PyObject *tuple, int *modified)
|
2016-09-30 04:07:26 -03:00
|
|
|
{
|
2024-06-21 12:19:31 -03:00
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
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)) {
|
2024-05-06 21:12:39 -03:00
|
|
|
if (should_intern_string(v)) {
|
2016-09-30 04:07:26 -03:00
|
|
|
PyObject *w = v;
|
2024-06-21 12:19:31 -03:00
|
|
|
_PyUnicode_InternMortal(interp, &v);
|
2016-09-30 04:07:26 -03:00
|
|
|
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)) {
|
2024-05-06 21:12:39 -03:00
|
|
|
if (intern_constants(v, NULL) < 0) {
|
2020-01-27 18:24:13 -04:00
|
|
|
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;
|
2024-05-06 21:12:39 -03:00
|
|
|
if (intern_constants(tmp, &tmp_modified) < 0) {
|
2020-01-27 18:24:13 -04:00
|
|
|
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);
|
|
|
|
}
|
2024-05-06 21:12:39 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
else if (PySlice_Check(v)) {
|
|
|
|
PySliceObject *slice = (PySliceObject *)v;
|
|
|
|
PyObject *tmp = PyTuple_New(3);
|
|
|
|
if (tmp == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
PyTuple_SET_ITEM(tmp, 0, Py_NewRef(slice->start));
|
|
|
|
PyTuple_SET_ITEM(tmp, 1, Py_NewRef(slice->stop));
|
|
|
|
PyTuple_SET_ITEM(tmp, 2, Py_NewRef(slice->step));
|
|
|
|
int tmp_modified = 0;
|
|
|
|
if (intern_constants(tmp, &tmp_modified) < 0) {
|
|
|
|
Py_DECREF(tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (tmp_modified) {
|
|
|
|
v = PySlice_New(PyTuple_GET_ITEM(tmp, 0),
|
|
|
|
PyTuple_GET_ITEM(tmp, 1),
|
|
|
|
PyTuple_GET_ITEM(tmp, 2));
|
|
|
|
if (v == NULL) {
|
|
|
|
Py_DECREF(tmp);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
PyTuple_SET_ITEM(tuple, i, v);
|
|
|
|
Py_DECREF(slice);
|
|
|
|
if (modified) {
|
|
|
|
*modified = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Py_DECREF(tmp);
|
|
|
|
}
|
|
|
|
|
2024-06-24 14:47:00 -03:00
|
|
|
// Intern non-string constants in the free-threaded build, but only if
|
2024-05-06 21:12:39 -03:00
|
|
|
// we are also immortalizing objects that use deferred reference
|
|
|
|
// counting.
|
|
|
|
PyThreadState *tstate = PyThreadState_GET();
|
|
|
|
if (!_Py_IsImmortal(v) && !PyCode_Check(v) &&
|
|
|
|
!PyUnicode_CheckExact(v) &&
|
2024-06-03 17:58:41 -03:00
|
|
|
_Py_atomic_load_int(&tstate->interp->gc.immortalize) >= 0)
|
2024-05-06 21:12:39 -03:00
|
|
|
{
|
|
|
|
PyObject *interned = intern_one_constant(v);
|
|
|
|
if (interned == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
else if (interned != v) {
|
|
|
|
PyTuple_SET_ITEM(tuple, i, interned);
|
|
|
|
Py_SETREF(v, interned);
|
|
|
|
if (modified) {
|
|
|
|
*modified = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2016-09-30 04:07:26 -03:00
|
|
|
}
|
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;
|
|
|
|
}
|
|
|
|
|
2022-10-11 00:26:08 -03:00
|
|
|
static int
|
|
|
|
init_co_cached(PyCodeObject *self) {
|
|
|
|
if (self->_co_cached == NULL) {
|
|
|
|
self->_co_cached = PyMem_New(_PyCoCached, 1);
|
|
|
|
if (self->_co_cached == NULL) {
|
|
|
|
PyErr_NoMemory();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
self->_co_cached->_co_code = NULL;
|
|
|
|
self->_co_cached->_co_cellvars = NULL;
|
|
|
|
self->_co_cached->_co_freevars = NULL;
|
|
|
|
self->_co_cached->_co_varnames = NULL;
|
|
|
|
}
|
|
|
|
return 0;
|
2021-05-19 19:44:56 -03:00
|
|
|
|
2022-10-11 00:26:08 -03:00
|
|
|
}
|
2021-05-19 19:44:56 -03:00
|
|
|
/******************
|
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
|
|
|
{
|
2022-11-10 11:27:32 -04:00
|
|
|
PyTuple_SET_ITEM(names, offset, Py_NewRef(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,
|
2023-01-04 11:41:39 -04:00
|
|
|
int *pnlocals, int *pncellvars,
|
2021-06-07 15:22:26 -03:00
|
|
|
int *pnfreevars)
|
|
|
|
{
|
|
|
|
int nlocals = 0;
|
|
|
|
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-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;
|
|
|
|
}
|
|
|
|
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);
|
2022-11-10 11:27:32 -04:00
|
|
|
PyTuple_SET_ITEM(names, index, Py_NewRef(name));
|
2021-06-07 15:22:26 -03:00
|
|
|
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) ||
|
|
|
|
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,
|
2023-01-04 11:41:39 -04:00
|
|
|
&nlocals, 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;
|
|
|
|
}
|
|
|
|
|
2022-11-02 14:42:57 -03:00
|
|
|
extern void _PyCode_Quicken(PyCodeObject *code);
|
|
|
|
|
2021-05-27 12:54:34 -03:00
|
|
|
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);
|
2023-01-04 11:41:39 -04:00
|
|
|
int nlocals, ncellvars, nfreevars;
|
2021-06-07 15:22:26 -03:00
|
|
|
get_localsplus_counts(con->localsplusnames, con->localspluskinds,
|
2023-01-04 11:41:39 -04:00
|
|
|
&nlocals, &ncellvars, &nfreevars);
|
2023-08-17 15:29:58 -03:00
|
|
|
if (con->stacksize == 0) {
|
|
|
|
con->stacksize = 1;
|
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
|
2024-06-21 12:19:31 -03:00
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
2022-11-10 11:27:32 -04:00
|
|
|
co->co_filename = Py_NewRef(con->filename);
|
|
|
|
co->co_name = Py_NewRef(con->name);
|
|
|
|
co->co_qualname = Py_NewRef(con->qualname);
|
2024-06-21 12:19:31 -03:00
|
|
|
_PyUnicode_InternMortal(interp, &co->co_filename);
|
|
|
|
_PyUnicode_InternMortal(interp, &co->co_name);
|
|
|
|
_PyUnicode_InternMortal(interp, &co->co_qualname);
|
2021-05-27 12:54:34 -03:00
|
|
|
co->co_flags = con->flags;
|
|
|
|
|
|
|
|
co->co_firstlineno = con->firstlineno;
|
2022-11-10 11:27:32 -04:00
|
|
|
co->co_linetable = Py_NewRef(con->linetable);
|
2021-05-27 12:54:34 -03:00
|
|
|
|
2022-11-10 11:27:32 -04:00
|
|
|
co->co_consts = Py_NewRef(con->consts);
|
|
|
|
co->co_names = Py_NewRef(con->names);
|
2021-05-27 12:54:34 -03:00
|
|
|
|
2022-11-10 11:27:32 -04:00
|
|
|
co->co_localsplusnames = Py_NewRef(con->localsplusnames);
|
|
|
|
co->co_localspluskinds = Py_NewRef(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;
|
|
|
|
|
2022-11-10 11:27:32 -04:00
|
|
|
co->co_exceptiontable = Py_NewRef(con->exceptiontable);
|
2021-05-27 12:54:34 -03:00
|
|
|
|
|
|
|
/* derived values */
|
2021-06-07 15:22:26 -03:00
|
|
|
co->co_nlocalsplus = nlocalsplus;
|
|
|
|
co->co_nlocals = nlocals;
|
2022-06-20 08:59:25 -03:00
|
|
|
co->co_framesize = nlocalsplus + con->stacksize + FRAME_SPECIALS_SIZE;
|
2021-06-07 15:22:26 -03:00
|
|
|
co->co_ncellvars = ncellvars;
|
|
|
|
co->co_nfreevars = nfreevars;
|
2024-05-03 17:21:04 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
PyMutex_Lock(&interp->func_state.mutex);
|
|
|
|
#endif
|
2024-03-18 15:11:10 -03:00
|
|
|
co->co_version = interp->func_state.next_version;
|
|
|
|
if (interp->func_state.next_version != 0) {
|
|
|
|
interp->func_state.next_version++;
|
2022-12-09 08:18:45 -04:00
|
|
|
}
|
2024-05-03 17:21:04 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
PyMutex_Unlock(&interp->func_state.mutex);
|
|
|
|
#endif
|
2023-04-12 08:04:55 -03:00
|
|
|
co->_co_monitoring = NULL;
|
|
|
|
co->_co_instrumentation_version = 0;
|
2021-05-27 12:54:34 -03:00
|
|
|
/* not set */
|
|
|
|
co->co_weakreflist = NULL;
|
|
|
|
co->co_extra = NULL;
|
2022-10-11 00:26:08 -03:00
|
|
|
co->_co_cached = NULL;
|
2023-06-02 07:46:18 -03:00
|
|
|
co->co_executors = NULL;
|
2021-06-14 07:04:09 -03:00
|
|
|
|
2022-03-21 08:11:17 -03:00
|
|
|
memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code),
|
|
|
|
PyBytes_GET_SIZE(con->code));
|
2022-06-14 07:09:30 -03:00
|
|
|
int entry_point = 0;
|
|
|
|
while (entry_point < Py_SIZE(co) &&
|
2023-02-20 10:56:48 -04:00
|
|
|
_PyCode_CODE(co)[entry_point].op.code != RESUME) {
|
2022-06-14 07:09:30 -03:00
|
|
|
entry_point++;
|
|
|
|
}
|
|
|
|
co->_co_firsttraceable = entry_point;
|
2022-11-02 14:42:57 -03:00
|
|
|
_PyCode_Quicken(co);
|
2022-12-02 13:28:27 -04:00
|
|
|
notify_code_watchers(PY_CODE_EVENT_CREATE, co);
|
2021-05-27 12:54:34 -03:00
|
|
|
}
|
|
|
|
|
2022-04-21 12:10:37 -03:00
|
|
|
static int
|
|
|
|
scan_varint(const uint8_t *ptr)
|
|
|
|
{
|
2022-06-28 10:24:54 -03:00
|
|
|
unsigned int read = *ptr++;
|
|
|
|
unsigned int val = read & 63;
|
|
|
|
unsigned int shift = 0;
|
2022-04-21 12:10:37 -03:00
|
|
|
while (read & 64) {
|
|
|
|
read = *ptr++;
|
|
|
|
shift += 6;
|
|
|
|
val |= (read & 63) << shift;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
scan_signed_varint(const uint8_t *ptr)
|
|
|
|
{
|
2022-06-28 10:24:54 -03:00
|
|
|
unsigned int uval = scan_varint(ptr);
|
2022-04-21 12:10:37 -03:00
|
|
|
if (uval & 1) {
|
|
|
|
return -(int)(uval >> 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return uval >> 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_line_delta(const uint8_t *ptr)
|
|
|
|
{
|
|
|
|
int code = ((*ptr) >> 3) & 15;
|
|
|
|
switch (code) {
|
|
|
|
case PY_CODE_LOCATION_INFO_NONE:
|
|
|
|
return 0;
|
|
|
|
case PY_CODE_LOCATION_INFO_NO_COLUMNS:
|
|
|
|
case PY_CODE_LOCATION_INFO_LONG:
|
|
|
|
return scan_signed_varint(ptr+1);
|
|
|
|
case PY_CODE_LOCATION_INFO_ONE_LINE0:
|
|
|
|
return 0;
|
|
|
|
case PY_CODE_LOCATION_INFO_ONE_LINE1:
|
|
|
|
return 1;
|
|
|
|
case PY_CODE_LOCATION_INFO_ONE_LINE2:
|
|
|
|
return 2;
|
|
|
|
default:
|
|
|
|
/* Same line */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
remove_column_info(PyObject *locations)
|
|
|
|
{
|
2024-06-24 13:11:47 -03:00
|
|
|
Py_ssize_t offset = 0;
|
2022-04-21 12:10:37 -03:00
|
|
|
const uint8_t *data = (const uint8_t *)PyBytes_AS_STRING(locations);
|
|
|
|
PyObject *res = PyBytes_FromStringAndSize(NULL, 32);
|
|
|
|
if (res == NULL) {
|
|
|
|
PyErr_NoMemory();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
uint8_t *output = (uint8_t *)PyBytes_AS_STRING(res);
|
|
|
|
while (offset < PyBytes_GET_SIZE(locations)) {
|
|
|
|
Py_ssize_t write_offset = output - (uint8_t *)PyBytes_AS_STRING(res);
|
|
|
|
if (write_offset + 16 >= PyBytes_GET_SIZE(res)) {
|
|
|
|
if (_PyBytes_Resize(&res, PyBytes_GET_SIZE(res) * 2) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
output = (uint8_t *)PyBytes_AS_STRING(res) + write_offset;
|
|
|
|
}
|
|
|
|
int code = (data[offset] >> 3) & 15;
|
|
|
|
if (code == PY_CODE_LOCATION_INFO_NONE) {
|
|
|
|
*output++ = data[offset];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
int blength = (data[offset] & 7)+1;
|
|
|
|
output += write_location_entry_start(
|
|
|
|
output, PY_CODE_LOCATION_INFO_NO_COLUMNS, blength);
|
|
|
|
int ldelta = get_line_delta(&data[offset]);
|
|
|
|
output += write_signed_varint(output, ldelta);
|
|
|
|
}
|
|
|
|
offset++;
|
|
|
|
while (offset < PyBytes_GET_SIZE(locations) &&
|
|
|
|
(data[offset] & 128) == 0) {
|
|
|
|
offset++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Py_ssize_t write_offset = output - (uint8_t *)PyBytes_AS_STRING(res);
|
|
|
|
if (_PyBytes_Resize(&res, write_offset)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2024-05-06 21:12:39 -03:00
|
|
|
static int
|
|
|
|
intern_code_constants(struct _PyCodeConstructor *con)
|
2021-05-27 12:54:34 -03:00
|
|
|
{
|
2024-05-06 21:12:39 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
|
|
|
struct _py_code_state *state = &interp->code_state;
|
|
|
|
PyMutex_Lock(&state->mutex);
|
|
|
|
#endif
|
2021-05-27 12:54:34 -03:00
|
|
|
if (intern_strings(con->names) < 0) {
|
2024-05-06 21:12:39 -03:00
|
|
|
goto error;
|
2020-01-27 18:24:13 -04:00
|
|
|
}
|
2024-05-06 21:12:39 -03:00
|
|
|
if (intern_constants(con->consts, NULL) < 0) {
|
|
|
|
goto error;
|
2020-01-27 18:24:13 -04:00
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
if (intern_strings(con->localsplusnames) < 0) {
|
2024-05-06 21:12:39 -03:00
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
PyMutex_Unlock(&state->mutex);
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
PyMutex_Unlock(&state->mutex);
|
|
|
|
#endif
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The caller is responsible for ensuring that the given data is valid. */
|
|
|
|
|
|
|
|
PyCodeObject *
|
|
|
|
_PyCode_New(struct _PyCodeConstructor *con)
|
|
|
|
{
|
|
|
|
if (intern_code_constants(con) < 0) {
|
2020-01-27 18:24:13 -04:00
|
|
|
return NULL;
|
|
|
|
}
|
2017-12-02 21:12:20 -04:00
|
|
|
|
2022-04-21 12:10:37 -03:00
|
|
|
PyObject *replacement_locations = NULL;
|
|
|
|
// Compact the linetable if we are opted out of debug
|
2021-07-07 16:07:12 -03:00
|
|
|
// ranges.
|
2021-12-02 06:43:37 -04:00
|
|
|
if (!_Py_GetConfig()->code_debug_ranges) {
|
2022-04-21 12:10:37 -03:00
|
|
|
replacement_locations = remove_column_info(con->linetable);
|
|
|
|
if (replacement_locations == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
con->linetable = replacement_locations;
|
2021-07-07 16:07:12 -03:00
|
|
|
}
|
|
|
|
|
2022-03-21 08:11:17 -03:00
|
|
|
Py_ssize_t size = PyBytes_GET_SIZE(con->code) / sizeof(_Py_CODEUNIT);
|
2024-04-16 13:42:53 -03:00
|
|
|
PyCodeObject *co;
|
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
co = PyObject_GC_NewVar(PyCodeObject, &PyCode_Type, size);
|
|
|
|
#else
|
|
|
|
co = PyObject_NewVar(PyCodeObject, &PyCode_Type, size);
|
|
|
|
#endif
|
2021-05-27 12:54:34 -03:00
|
|
|
if (co == NULL) {
|
2022-04-21 12:10:37 -03:00
|
|
|
Py_XDECREF(replacement_locations);
|
2021-05-27 12:54:34 -03:00
|
|
|
PyErr_NoMemory();
|
2018-07-16 03:10:19 -03:00
|
|
|
return NULL;
|
|
|
|
}
|
2021-05-27 12:54:34 -03:00
|
|
|
init_code(co, con);
|
2024-04-16 13:42:53 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
_PyObject_SetDeferredRefcount((PyObject *)co);
|
|
|
|
_PyObject_GC_TRACK(co);
|
|
|
|
#endif
|
2022-04-21 12:10:37 -03:00
|
|
|
Py_XDECREF(replacement_locations);
|
2021-05-27 12:54:34 -03:00
|
|
|
return co;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************
|
|
|
|
* the legacy "constructors"
|
|
|
|
******************/
|
|
|
|
|
|
|
|
PyCodeObject *
|
2023-02-28 04:31:01 -04:00
|
|
|
PyUnstable_Code_NewWithPosOnlyArgs(
|
|
|
|
int argcount, int posonlyargcount, int kwonlyargcount,
|
2021-05-27 12:54:34 -03:00
|
|
|
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,
|
2022-04-21 12:10:37 -03:00
|
|
|
PyObject *linetable,
|
|
|
|
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);
|
|
|
|
}
|
2023-11-08 16:11:59 -04:00
|
|
|
|
|
|
|
// gh-110543: Make sure the CO_FAST_HIDDEN flag is set correctly.
|
|
|
|
if (!(flags & CO_OPTIMIZED)) {
|
|
|
|
Py_ssize_t code_len = PyBytes_GET_SIZE(code);
|
|
|
|
_Py_CODEUNIT *code_data = (_Py_CODEUNIT *)PyBytes_AS_STRING(code);
|
|
|
|
Py_ssize_t num_code_units = code_len / sizeof(_Py_CODEUNIT);
|
|
|
|
int extended_arg = 0;
|
|
|
|
for (int i = 0; i < num_code_units; i += 1 + _PyOpcode_Caches[code_data[i].op.code]) {
|
|
|
|
_Py_CODEUNIT *instr = &code_data[i];
|
|
|
|
uint8_t opcode = instr->op.code;
|
|
|
|
if (opcode == EXTENDED_ARG) {
|
|
|
|
extended_arg = extended_arg << 8 | instr->op.arg;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (opcode == LOAD_FAST_AND_CLEAR) {
|
|
|
|
int oparg = extended_arg << 8 | instr->op.arg;
|
|
|
|
if (oparg >= nlocalsplus) {
|
|
|
|
PyErr_Format(PyExc_ValueError,
|
|
|
|
"code: LOAD_FAST_AND_CLEAR oparg %d out of range",
|
|
|
|
oparg);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
_PyLocals_Kind kind = _PyLocals_GetKind(localspluskinds, oparg);
|
|
|
|
_PyLocals_SetKind(localspluskinds, oparg, kind | CO_FAST_HIDDEN);
|
|
|
|
}
|
|
|
|
extended_arg = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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,
|
|
|
|
|
|
|
|
.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 *
|
2023-02-28 04:31:01 -04:00
|
|
|
PyUnstable_Code_New(int argcount, int kwonlyargcount,
|
2019-07-01 07:35:05 -03:00
|
|
|
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,
|
2022-04-21 12:10:37 -03:00
|
|
|
int firstlineno,
|
|
|
|
PyObject *linetable,
|
|
|
|
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,
|
2022-04-21 12:10:37 -03:00
|
|
|
name, qualname, firstlineno,
|
|
|
|
linetable,
|
|
|
|
exceptiontable);
|
2019-07-01 07:35:05 -03:00
|
|
|
}
|
|
|
|
|
2022-10-04 21:30:03 -03:00
|
|
|
// NOTE: When modifying the construction of PyCode_NewEmpty, please also change
|
|
|
|
// test.test_code.CodeLocationTest.test_code_new_empty to keep it in sync!
|
|
|
|
|
|
|
|
static const uint8_t assert0[6] = {
|
2023-11-02 07:18:43 -03:00
|
|
|
RESUME, RESUME_AT_FUNC_START,
|
2024-05-21 21:46:39 -03:00
|
|
|
LOAD_COMMON_CONSTANT, CONSTANT_ASSERTIONERROR,
|
2022-07-01 07:08:20 -03:00
|
|
|
RAISE_VARARGS, 1
|
2022-04-21 15:08:36 -03:00
|
|
|
};
|
|
|
|
|
2022-10-04 21:30:03 -03:00
|
|
|
static const uint8_t linetable[2] = {
|
|
|
|
(1 << 7) // New entry.
|
|
|
|
| (PY_CODE_LOCATION_INFO_NO_COLUMNS << 3)
|
|
|
|
| (3 - 1), // Three code units.
|
|
|
|
0, // Offset from co_firstlineno.
|
|
|
|
};
|
|
|
|
|
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 *nulltuple = NULL;
|
2010-05-09 12:52:27 -03:00
|
|
|
PyObject *filename_ob = NULL;
|
|
|
|
PyObject *funcname_ob = NULL;
|
2022-04-21 15:08:36 -03:00
|
|
|
PyObject *code_ob = NULL;
|
2022-10-04 21:30:03 -03:00
|
|
|
PyObject *linetable_ob = NULL;
|
2010-05-09 12:52:27 -03:00
|
|
|
PyCodeObject *result = NULL;
|
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
|
|
|
}
|
2022-10-04 21:30:03 -03:00
|
|
|
code_ob = PyBytes_FromStringAndSize((const char *)assert0, 6);
|
2022-04-21 15:08:36 -03:00
|
|
|
if (code_ob == NULL) {
|
|
|
|
goto failed;
|
|
|
|
}
|
2022-10-04 21:30:03 -03:00
|
|
|
linetable_ob = PyBytes_FromStringAndSize((const char *)linetable, 2);
|
|
|
|
if (linetable_ob == NULL) {
|
|
|
|
goto failed;
|
|
|
|
}
|
2010-05-09 12:52:27 -03:00
|
|
|
|
2022-02-22 20:23:51 -04:00
|
|
|
#define emptystring (PyObject *)&_Py_SINGLETON(bytes_empty)
|
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,
|
2022-04-21 15:08:36 -03:00
|
|
|
.code = code_ob,
|
2021-05-27 12:54:34 -03:00
|
|
|
.firstlineno = firstlineno,
|
2022-10-04 21:30:03 -03:00
|
|
|
.linetable = linetable_ob,
|
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,
|
2022-04-21 15:08:36 -03:00
|
|
|
.stacksize = 1,
|
2021-05-27 12:54:34 -03:00
|
|
|
};
|
|
|
|
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(nulltuple);
|
2010-05-09 12:52:27 -03:00
|
|
|
Py_XDECREF(funcname_ob);
|
|
|
|
Py_XDECREF(filename_ob);
|
2022-04-21 15:08:36 -03:00
|
|
|
Py_XDECREF(code_ob);
|
2022-10-04 21:30:03 -03:00
|
|
|
Py_XDECREF(linetable_ob);
|
2010-05-09 12:52:27 -03:00
|
|
|
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
|
|
|
******************/
|
|
|
|
|
|
|
|
int
|
|
|
|
PyCode_Addr2Line(PyCodeObject *co, int addrq)
|
|
|
|
{
|
|
|
|
if (addrq < 0) {
|
|
|
|
return co->co_firstlineno;
|
|
|
|
}
|
2022-03-21 08:11:17 -03:00
|
|
|
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
|
2021-05-19 19:44:56 -03:00
|
|
|
PyCodeAddressRange bounds;
|
|
|
|
_PyCode_InitAddressRange(co, &bounds);
|
|
|
|
return _PyCode_CheckLineNumber(addrq, &bounds);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2022-02-25 10:41:32 -04:00
|
|
|
_PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int firstlineno, PyCodeAddressRange *range)
|
2021-05-19 19:44:56 -03:00
|
|
|
{
|
2022-04-21 12:10:37 -03:00
|
|
|
range->opaque.lo_next = (const uint8_t *)linetable;
|
2021-05-19 19:44:56 -03:00
|
|
|
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)
|
|
|
|
{
|
2022-04-21 12:10:37 -03:00
|
|
|
assert(co->co_linetable != NULL);
|
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);
|
2022-02-25 10:41:32 -04:00
|
|
|
_PyLineTable_InitAddressRange(linetable, length, co->co_firstlineno, bounds);
|
2021-05-19 19:44:56 -03:00
|
|
|
return bounds->ar_line;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update *bounds to describe the first and one-past-the-last instructions in
|
|
|
|
the same line as lasti. Return the number of that line, or -1 if lasti is out of bounds. */
|
|
|
|
int
|
|
|
|
_PyCode_CheckLineNumber(int lasti, PyCodeAddressRange *bounds)
|
|
|
|
{
|
|
|
|
while (bounds->ar_end <= lasti) {
|
2022-02-25 10:41:32 -04:00
|
|
|
if (!_PyLineTable_NextAddressRange(bounds)) {
|
2021-05-19 19:44:56 -03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (bounds->ar_start > lasti) {
|
2022-02-25 10:41:32 -04:00
|
|
|
if (!_PyLineTable_PreviousAddressRange(bounds)) {
|
2021-05-19 19:44:56 -03:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bounds->ar_line;
|
|
|
|
}
|
|
|
|
|
2022-04-21 12:10:37 -03:00
|
|
|
static int
|
|
|
|
is_no_line_marker(uint8_t b)
|
|
|
|
{
|
|
|
|
return (b >> 3) == 0x1f;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define ASSERT_VALID_BOUNDS(bounds) \
|
|
|
|
assert(bounds->opaque.lo_next <= bounds->opaque.limit && \
|
|
|
|
(bounds->ar_line == -1 || bounds->ar_line == bounds->opaque.computed_line) && \
|
|
|
|
(bounds->opaque.lo_next == bounds->opaque.limit || \
|
|
|
|
(*bounds->opaque.lo_next) & 128))
|
|
|
|
|
|
|
|
static int
|
|
|
|
next_code_delta(PyCodeAddressRange *bounds)
|
|
|
|
{
|
|
|
|
assert((*bounds->opaque.lo_next) & 128);
|
|
|
|
return (((*bounds->opaque.lo_next) & 7) + 1) * sizeof(_Py_CODEUNIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
previous_code_delta(PyCodeAddressRange *bounds)
|
|
|
|
{
|
2022-06-20 13:13:39 -03:00
|
|
|
if (bounds->ar_start == 0) {
|
|
|
|
// If we looking at the first entry, the
|
|
|
|
// "previous" entry has an implicit length of 1.
|
|
|
|
return 1;
|
|
|
|
}
|
2022-04-21 12:10:37 -03:00
|
|
|
const uint8_t *ptr = bounds->opaque.lo_next-1;
|
|
|
|
while (((*ptr) & 128) == 0) {
|
|
|
|
ptr--;
|
|
|
|
}
|
|
|
|
return (((*ptr) & 7) + 1) * sizeof(_Py_CODEUNIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
read_byte(PyCodeAddressRange *bounds)
|
|
|
|
{
|
|
|
|
return *bounds->opaque.lo_next++;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
read_varint(PyCodeAddressRange *bounds)
|
|
|
|
{
|
2022-06-28 10:24:54 -03:00
|
|
|
unsigned int read = read_byte(bounds);
|
|
|
|
unsigned int val = read & 63;
|
|
|
|
unsigned int shift = 0;
|
2022-04-21 12:10:37 -03:00
|
|
|
while (read & 64) {
|
|
|
|
read = read_byte(bounds);
|
|
|
|
shift += 6;
|
|
|
|
val |= (read & 63) << shift;
|
|
|
|
}
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
read_signed_varint(PyCodeAddressRange *bounds)
|
|
|
|
{
|
2022-06-28 10:24:54 -03:00
|
|
|
unsigned int uval = read_varint(bounds);
|
2022-04-21 12:10:37 -03:00
|
|
|
if (uval & 1) {
|
|
|
|
return -(int)(uval >> 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return uval >> 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
static void
|
|
|
|
retreat(PyCodeAddressRange *bounds)
|
|
|
|
{
|
2022-04-21 12:10:37 -03:00
|
|
|
ASSERT_VALID_BOUNDS(bounds);
|
2022-06-20 13:13:39 -03:00
|
|
|
assert(bounds->ar_start >= 0);
|
2022-04-21 12:10:37 -03:00
|
|
|
do {
|
|
|
|
bounds->opaque.lo_next--;
|
|
|
|
} while (((*bounds->opaque.lo_next) & 128) == 0);
|
|
|
|
bounds->opaque.computed_line -= get_line_delta(bounds->opaque.lo_next);
|
2021-05-19 19:44:56 -03:00
|
|
|
bounds->ar_end = bounds->ar_start;
|
2022-04-21 12:10:37 -03:00
|
|
|
bounds->ar_start -= previous_code_delta(bounds);
|
|
|
|
if (is_no_line_marker(bounds->opaque.lo_next[-1])) {
|
2021-05-19 19:44:56 -03:00
|
|
|
bounds->ar_line = -1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bounds->ar_line = bounds->opaque.computed_line;
|
|
|
|
}
|
2022-04-21 12:10:37 -03:00
|
|
|
ASSERT_VALID_BOUNDS(bounds);
|
2021-05-19 19:44:56 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
advance(PyCodeAddressRange *bounds)
|
|
|
|
{
|
2022-04-21 12:10:37 -03:00
|
|
|
ASSERT_VALID_BOUNDS(bounds);
|
|
|
|
bounds->opaque.computed_line += get_line_delta(bounds->opaque.lo_next);
|
|
|
|
if (is_no_line_marker(*bounds->opaque.lo_next)) {
|
2021-05-19 19:44:56 -03:00
|
|
|
bounds->ar_line = -1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
bounds->ar_line = bounds->opaque.computed_line;
|
|
|
|
}
|
2022-04-21 12:10:37 -03:00
|
|
|
bounds->ar_start = bounds->ar_end;
|
|
|
|
bounds->ar_end += next_code_delta(bounds);
|
|
|
|
do {
|
|
|
|
bounds->opaque.lo_next++;
|
|
|
|
} while (bounds->opaque.lo_next < bounds->opaque.limit &&
|
|
|
|
((*bounds->opaque.lo_next) & 128) == 0);
|
|
|
|
ASSERT_VALID_BOUNDS(bounds);
|
2021-05-19 19:44:56 -03:00
|
|
|
}
|
|
|
|
|
2022-04-21 12:10:37 -03:00
|
|
|
static void
|
|
|
|
advance_with_locations(PyCodeAddressRange *bounds, int *endline, int *column, int *endcolumn)
|
|
|
|
{
|
|
|
|
ASSERT_VALID_BOUNDS(bounds);
|
|
|
|
int first_byte = read_byte(bounds);
|
|
|
|
int code = (first_byte >> 3) & 15;
|
|
|
|
bounds->ar_start = bounds->ar_end;
|
|
|
|
bounds->ar_end = bounds->ar_start + ((first_byte & 7) + 1) * sizeof(_Py_CODEUNIT);
|
|
|
|
switch(code) {
|
|
|
|
case PY_CODE_LOCATION_INFO_NONE:
|
|
|
|
bounds->ar_line = *endline = -1;
|
|
|
|
*column = *endcolumn = -1;
|
|
|
|
break;
|
|
|
|
case PY_CODE_LOCATION_INFO_LONG:
|
|
|
|
{
|
|
|
|
bounds->opaque.computed_line += read_signed_varint(bounds);
|
|
|
|
bounds->ar_line = bounds->opaque.computed_line;
|
|
|
|
*endline = bounds->ar_line + read_varint(bounds);
|
|
|
|
*column = read_varint(bounds)-1;
|
|
|
|
*endcolumn = read_varint(bounds)-1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PY_CODE_LOCATION_INFO_NO_COLUMNS:
|
|
|
|
{
|
|
|
|
/* No column */
|
|
|
|
bounds->opaque.computed_line += read_signed_varint(bounds);
|
|
|
|
*endline = bounds->ar_line = bounds->opaque.computed_line;
|
|
|
|
*column = *endcolumn = -1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PY_CODE_LOCATION_INFO_ONE_LINE0:
|
|
|
|
case PY_CODE_LOCATION_INFO_ONE_LINE1:
|
|
|
|
case PY_CODE_LOCATION_INFO_ONE_LINE2:
|
|
|
|
{
|
|
|
|
/* one line form */
|
|
|
|
int line_delta = code - 10;
|
|
|
|
bounds->opaque.computed_line += line_delta;
|
|
|
|
*endline = bounds->ar_line = bounds->opaque.computed_line;
|
|
|
|
*column = read_byte(bounds);
|
|
|
|
*endcolumn = read_byte(bounds);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
/* Short forms */
|
|
|
|
int second_byte = read_byte(bounds);
|
|
|
|
assert((second_byte & 128) == 0);
|
|
|
|
*endline = bounds->ar_line = bounds->opaque.computed_line;
|
|
|
|
*column = code << 3 | (second_byte >> 4);
|
|
|
|
*endcolumn = *column + (second_byte & 15);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ASSERT_VALID_BOUNDS(bounds);
|
|
|
|
}
|
|
|
|
int
|
|
|
|
PyCode_Addr2Location(PyCodeObject *co, int addrq,
|
|
|
|
int *start_line, int *start_column,
|
|
|
|
int *end_line, int *end_column)
|
|
|
|
{
|
|
|
|
if (addrq < 0) {
|
|
|
|
*start_line = *end_line = co->co_firstlineno;
|
|
|
|
*start_column = *end_column = 0;
|
2022-07-21 10:49:49 -03:00
|
|
|
return 1;
|
2022-04-21 12:10:37 -03:00
|
|
|
}
|
|
|
|
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
|
|
|
|
PyCodeAddressRange bounds;
|
|
|
|
_PyCode_InitAddressRange(co, &bounds);
|
|
|
|
_PyCode_CheckLineNumber(addrq, &bounds);
|
|
|
|
retreat(&bounds);
|
|
|
|
advance_with_locations(&bounds, end_line, start_column, end_column);
|
|
|
|
*start_line = bounds.ar_line;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
static inline int
|
|
|
|
at_end(PyCodeAddressRange *bounds) {
|
|
|
|
return bounds->opaque.lo_next >= bounds->opaque.limit;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2022-02-25 10:41:32 -04:00
|
|
|
_PyLineTable_PreviousAddressRange(PyCodeAddressRange *range)
|
2021-05-19 19:44:56 -03:00
|
|
|
{
|
|
|
|
if (range->ar_start <= 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
retreat(range);
|
2022-04-21 12:10:37 -03:00
|
|
|
assert(range->ar_end > range->ar_start);
|
2021-05-19 19:44:56 -03:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2022-02-25 10:41:32 -04:00
|
|
|
_PyLineTable_NextAddressRange(PyCodeAddressRange *range)
|
2021-05-19 19:44:56 -03:00
|
|
|
{
|
|
|
|
if (at_end(range)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
advance(range);
|
2022-04-21 12:10:37 -03:00
|
|
|
assert(range->ar_end > range->ar_start);
|
2021-05-19 19:44:56 -03:00
|
|
|
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);
|
2022-02-25 10:41:32 -04:00
|
|
|
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;
|
|
|
|
} 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
|
|
|
|
2023-01-10 06:56:53 -04:00
|
|
|
static PyObject *
|
|
|
|
_source_offset_converter(int *value) {
|
|
|
|
if (*value == -1) {
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
}
|
|
|
|
return PyLong_FromLong(*value);
|
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
static PyObject *
|
|
|
|
lineiter_next(lineiterator *li)
|
|
|
|
{
|
|
|
|
PyCodeAddressRange *bounds = &li->li_line;
|
2022-02-25 10:41:32 -04:00
|
|
|
if (!_PyLineTable_NextAddressRange(bounds)) {
|
2010-05-09 12:52:27 -03:00
|
|
|
return NULL;
|
2021-05-19 19:44:56 -03:00
|
|
|
}
|
2023-01-10 06:56:53 -04:00
|
|
|
int start = bounds->ar_start;
|
|
|
|
int line = bounds->ar_line;
|
|
|
|
// Merge overlapping entries:
|
|
|
|
while (_PyLineTable_NextAddressRange(bounds)) {
|
|
|
|
if (bounds->ar_line != line) {
|
|
|
|
_PyLineTable_PreviousAddressRange(bounds);
|
|
|
|
break;
|
|
|
|
}
|
2021-05-19 19:44:56 -03:00
|
|
|
}
|
2023-01-10 06:56:53 -04:00
|
|
|
return Py_BuildValue("iiO&", start, bounds->ar_end,
|
|
|
|
_source_offset_converter, &line);
|
2021-05-19 19:44:56 -03:00
|
|
|
}
|
2010-05-09 12:52:27 -03:00
|
|
|
|
2022-05-19 10:55:22 -03:00
|
|
|
PyTypeObject _PyLineIterator = {
|
2021-05-19 19:44:56 -03:00
|
|
|
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)
|
|
|
|
{
|
2022-05-19 10:55:22 -03:00
|
|
|
lineiterator *li = (lineiterator *)PyType_GenericAlloc(&_PyLineIterator, 0);
|
2021-05-19 19:44:56 -03:00
|
|
|
if (li == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2022-11-10 11:27:32 -04:00
|
|
|
li->li_code = (PyCodeObject*)Py_NewRef(code);
|
2021-05-19 19:44:56 -03:00
|
|
|
_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;
|
2022-04-21 12:10:37 -03:00
|
|
|
PyCodeAddressRange pi_range;
|
2021-07-02 11:10:11 -03:00
|
|
|
int pi_offset;
|
2022-04-21 12:10:37 -03:00
|
|
|
int pi_endline;
|
|
|
|
int pi_column;
|
|
|
|
int pi_endcolumn;
|
2021-07-02 11:10:11 -03:00
|
|
|
} positionsiterator;
|
|
|
|
|
|
|
|
static void
|
|
|
|
positionsiter_dealloc(positionsiterator* pi)
|
|
|
|
{
|
|
|
|
Py_DECREF(pi->pi_code);
|
|
|
|
Py_TYPE(pi)->tp_free(pi);
|
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject*
|
|
|
|
positionsiter_next(positionsiterator* pi)
|
|
|
|
{
|
2022-04-21 12:10:37 -03:00
|
|
|
if (pi->pi_offset >= pi->pi_range.ar_end) {
|
|
|
|
assert(pi->pi_offset == pi->pi_range.ar_end);
|
|
|
|
if (at_end(&pi->pi_range)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
advance_with_locations(&pi->pi_range, &pi->pi_endline, &pi->pi_column, &pi->pi_endcolumn);
|
2021-07-02 11:10:11 -03:00
|
|
|
}
|
|
|
|
pi->pi_offset += 2;
|
|
|
|
return Py_BuildValue("(O&O&O&O&)",
|
2022-04-21 12:10:37 -03:00
|
|
|
_source_offset_converter, &pi->pi_range.ar_line,
|
|
|
|
_source_offset_converter, &pi->pi_endline,
|
|
|
|
_source_offset_converter, &pi->pi_column,
|
|
|
|
_source_offset_converter, &pi->pi_endcolumn);
|
2021-07-02 11:10:11 -03:00
|
|
|
}
|
|
|
|
|
2022-05-19 10:55:22 -03:00
|
|
|
PyTypeObject _PyPositionsIterator = {
|
2021-07-02 11:10:11 -03:00
|
|
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
2022-02-17 01:20:06 -04:00
|
|
|
"positions_iterator", /* tp_name */
|
2021-07-02 11:10:11 -03:00
|
|
|
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))
|
|
|
|
{
|
2022-05-19 10:55:22 -03:00
|
|
|
positionsiterator* pi = (positionsiterator*)PyType_GenericAlloc(&_PyPositionsIterator, 0);
|
2021-07-02 11:10:11 -03:00
|
|
|
if (pi == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2022-11-10 11:27:32 -04:00
|
|
|
pi->pi_code = (PyCodeObject*)Py_NewRef(code);
|
2022-04-21 12:10:37 -03:00
|
|
|
_PyCode_InitAddressRange(code, &pi->pi_range);
|
|
|
|
pi->pi_offset = pi->pi_range.ar_end;
|
2021-07-02 11:10:11 -03:00
|
|
|
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
|
2023-02-28 04:31:01 -04:00
|
|
|
PyUnstable_Code_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
|
2021-05-19 19:44:56 -03:00
|
|
|
{
|
|
|
|
if (!PyCode_Check(code)) {
|
|
|
|
PyErr_BadInternalCall();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
PyCodeObject *o = (PyCodeObject*) code;
|
|
|
|
_PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) o->co_extra;
|
|
|
|
|
2022-08-23 07:13:53 -03:00
|
|
|
if (co_extra == NULL || index < 0 || co_extra->ce_size <= index) {
|
2021-05-19 19:44:56 -03:00
|
|
|
*extra = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
*extra = co_extra->ce_extras[index];
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2023-02-28 04:31:01 -04:00
|
|
|
PyUnstable_Code_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
|
2021-05-19 19:44:56 -03:00
|
|
|
{
|
|
|
|
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
|
|
|
|
******************/
|
|
|
|
|
2022-10-11 00:26:08 -03:00
|
|
|
static PyObject *
|
|
|
|
get_cached_locals(PyCodeObject *co, PyObject **cached_field,
|
|
|
|
_PyLocals_Kind kind, int num)
|
|
|
|
{
|
|
|
|
assert(cached_field != NULL);
|
|
|
|
assert(co->_co_cached != NULL);
|
|
|
|
if (*cached_field != NULL) {
|
|
|
|
return Py_NewRef(*cached_field);
|
|
|
|
}
|
|
|
|
assert(*cached_field == NULL);
|
|
|
|
PyObject *varnames = get_localsplus_names(co, kind, num);
|
|
|
|
if (varnames == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
*cached_field = Py_NewRef(varnames);
|
|
|
|
return varnames;
|
|
|
|
}
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
PyObject *
|
|
|
|
_PyCode_GetVarnames(PyCodeObject *co)
|
|
|
|
{
|
2022-10-11 00:26:08 -03:00
|
|
|
if (init_co_cached(co)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return get_cached_locals(co, &co->_co_cached->_co_varnames, CO_FAST_LOCAL, co->co_nlocals);
|
2021-06-07 15:22:26 -03:00
|
|
|
}
|
|
|
|
|
2022-08-04 10:53:31 -03:00
|
|
|
PyObject *
|
|
|
|
PyCode_GetVarnames(PyCodeObject *code)
|
|
|
|
{
|
|
|
|
return _PyCode_GetVarnames(code);
|
|
|
|
}
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
PyObject *
|
|
|
|
_PyCode_GetCellvars(PyCodeObject *co)
|
|
|
|
{
|
2022-10-11 00:26:08 -03:00
|
|
|
if (init_co_cached(co)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return get_cached_locals(co, &co->_co_cached->_co_cellvars, CO_FAST_CELL, co->co_ncellvars);
|
2021-06-07 15:22:26 -03:00
|
|
|
}
|
|
|
|
|
2022-08-04 10:53:31 -03:00
|
|
|
PyObject *
|
|
|
|
PyCode_GetCellvars(PyCodeObject *code)
|
|
|
|
{
|
|
|
|
return _PyCode_GetCellvars(code);
|
|
|
|
}
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
PyObject *
|
|
|
|
_PyCode_GetFreevars(PyCodeObject *co)
|
|
|
|
{
|
2022-10-11 00:26:08 -03:00
|
|
|
if (init_co_cached(co)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return get_cached_locals(co, &co->_co_cached->_co_freevars, CO_FAST_FREE, co->co_nfreevars);
|
2022-03-21 08:11:17 -03:00
|
|
|
}
|
|
|
|
|
2022-08-04 10:53:31 -03:00
|
|
|
PyObject *
|
|
|
|
PyCode_GetFreevars(PyCodeObject *code)
|
|
|
|
{
|
|
|
|
return _PyCode_GetFreevars(code);
|
|
|
|
}
|
|
|
|
|
2024-04-30 22:26:34 -03:00
|
|
|
#ifdef _Py_TIER2
|
|
|
|
|
2023-06-19 06:32:20 -03:00
|
|
|
static void
|
|
|
|
clear_executors(PyCodeObject *co)
|
|
|
|
{
|
2024-02-12 05:04:36 -04:00
|
|
|
assert(co->co_executors);
|
2023-06-19 06:32:20 -03:00
|
|
|
for (int i = 0; i < co->co_executors->size; i++) {
|
2024-02-12 05:04:36 -04:00
|
|
|
if (co->co_executors->executors[i]) {
|
2024-05-01 07:34:50 -03:00
|
|
|
_Py_ExecutorDetach(co->co_executors->executors[i]);
|
|
|
|
assert(co->co_executors->executors[i] == NULL);
|
2024-02-12 05:04:36 -04:00
|
|
|
}
|
2023-06-19 06:32:20 -03:00
|
|
|
}
|
|
|
|
PyMem_Free(co->co_executors);
|
|
|
|
co->co_executors = NULL;
|
|
|
|
}
|
|
|
|
|
2023-09-06 21:53:54 -03:00
|
|
|
void
|
2024-02-12 05:04:36 -04:00
|
|
|
_PyCode_Clear_Executors(PyCodeObject *code)
|
|
|
|
{
|
2023-09-06 21:53:54 -03:00
|
|
|
clear_executors(code);
|
|
|
|
}
|
|
|
|
|
2024-04-30 22:26:34 -03:00
|
|
|
#endif
|
|
|
|
|
2022-05-03 11:59:12 -03:00
|
|
|
static void
|
2023-04-12 08:04:55 -03:00
|
|
|
deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions)
|
2022-03-21 08:11:17 -03:00
|
|
|
{
|
2023-04-12 08:04:55 -03:00
|
|
|
Py_ssize_t len = Py_SIZE(code);
|
2022-05-03 11:59:12 -03:00
|
|
|
for (int i = 0; i < len; i++) {
|
2023-04-12 08:04:55 -03:00
|
|
|
int opcode = _Py_GetBaseOpcode(code, i);
|
2023-06-19 06:32:20 -03:00
|
|
|
if (opcode == ENTER_EXECUTOR) {
|
|
|
|
_PyExecutorObject *exec = code->co_executors->executors[instructions[i].op.arg];
|
2023-09-22 18:13:31 -03:00
|
|
|
opcode = _PyOpcode_Deopt[exec->vm_data.opcode];
|
2023-06-19 06:32:20 -03:00
|
|
|
instructions[i].op.arg = exec->vm_data.oparg;
|
|
|
|
}
|
|
|
|
assert(opcode != ENTER_EXECUTOR);
|
2022-03-21 08:11:17 -03:00
|
|
|
int caches = _PyOpcode_Caches[opcode];
|
2023-02-20 10:56:48 -04:00
|
|
|
instructions[i].op.code = opcode;
|
2023-04-12 08:04:55 -03:00
|
|
|
for (int j = 1; j <= caches; j++) {
|
|
|
|
instructions[i+j].cache = 0;
|
2021-06-07 15:22:26 -03:00
|
|
|
}
|
2023-04-12 08:04:55 -03:00
|
|
|
i += caches;
|
2021-06-07 15:22:26 -03:00
|
|
|
}
|
2022-05-03 11:59:12 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
PyObject *
|
|
|
|
_PyCode_GetCode(PyCodeObject *co)
|
|
|
|
{
|
2022-10-11 00:26:08 -03:00
|
|
|
if (init_co_cached(co)) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if (co->_co_cached->_co_code != NULL) {
|
|
|
|
return Py_NewRef(co->_co_cached->_co_code);
|
2022-06-03 13:41:18 -03:00
|
|
|
}
|
2022-05-03 11:59:12 -03:00
|
|
|
PyObject *code = PyBytes_FromStringAndSize((const char *)_PyCode_CODE(co),
|
|
|
|
_PyCode_NBYTES(co));
|
|
|
|
if (code == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2023-04-12 08:04:55 -03:00
|
|
|
deopt_code(co, (_Py_CODEUNIT *)PyBytes_AS_STRING(code));
|
2022-10-11 00:26:08 -03:00
|
|
|
assert(co->_co_cached->_co_code == NULL);
|
|
|
|
co->_co_cached->_co_code = Py_NewRef(code);
|
2022-03-21 08:11:17 -03:00
|
|
|
return code;
|
2021-06-07 15:22:26 -03:00
|
|
|
}
|
|
|
|
|
2022-05-03 10:13:13 -03:00
|
|
|
PyObject *
|
|
|
|
PyCode_GetCode(PyCodeObject *co)
|
|
|
|
{
|
|
|
|
return _PyCode_GetCode(co);
|
|
|
|
}
|
2021-06-07 15:22:26 -03:00
|
|
|
|
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-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 *exceptiontable, PyObject *freevars,
|
|
|
|
PyObject *cellvars)
|
2022-04-21 12:10:37 -03:00
|
|
|
/*[clinic end generated code: output=069fa20d299f9dda input=e31da3c41ad8064a]*/
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
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,
|
2022-04-21 12:10:37 -03:00
|
|
|
linetable,
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2023-04-12 08:04:55 -03:00
|
|
|
static void
|
|
|
|
free_monitoring_data(_PyCoMonitoringData *data)
|
|
|
|
{
|
|
|
|
if (data == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (data->tools) {
|
|
|
|
PyMem_Free(data->tools);
|
|
|
|
}
|
|
|
|
if (data->lines) {
|
|
|
|
PyMem_Free(data->lines);
|
|
|
|
}
|
|
|
|
if (data->line_tools) {
|
|
|
|
PyMem_Free(data->line_tools);
|
|
|
|
}
|
|
|
|
if (data->per_instruction_opcodes) {
|
|
|
|
PyMem_Free(data->per_instruction_opcodes);
|
|
|
|
}
|
|
|
|
if (data->per_instruction_tools) {
|
|
|
|
PyMem_Free(data->per_instruction_tools);
|
|
|
|
}
|
|
|
|
PyMem_Free(data);
|
|
|
|
}
|
|
|
|
|
2005-10-20 16:59:25 -03:00
|
|
|
static void
|
|
|
|
code_dealloc(PyCodeObject *co)
|
|
|
|
{
|
2023-03-07 20:10:58 -04:00
|
|
|
assert(Py_REFCNT(co) == 0);
|
|
|
|
Py_SET_REFCNT(co, 1);
|
2022-12-02 13:28:27 -04:00
|
|
|
notify_code_watchers(PY_CODE_EVENT_DESTROY, co);
|
2023-03-07 20:10:58 -04:00
|
|
|
if (Py_REFCNT(co) > 1) {
|
|
|
|
Py_SET_REFCNT(co, Py_REFCNT(co) - 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Py_SET_REFCNT(co, 0);
|
2022-12-02 13:28:27 -04:00
|
|
|
|
2024-04-16 13:42:53 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
PyObject_GC_UnTrack(co);
|
|
|
|
#endif
|
|
|
|
|
gh-117045: Add code object to function version cache (#117028)
Changes to the function version cache:
- In addition to the function object, also store the code object,
and allow the latter to be retrieved even if the function has been evicted.
- Stop assigning new function versions after a critical attribute (e.g. `__code__`)
has been modified; the version is permanently reset to zero in this case.
- Changes to `__annotations__` are no longer considered critical. (This fixes gh-109998.)
Changes to the Tier 2 optimization machinery:
- If we cannot map a function version to a function, but it is still mapped to a code object,
we continue projecting the trace.
The operand of the `_PUSH_FRAME` and `_POP_FRAME` opcodes can be either NULL,
a function object, or a code object with the lowest bit set.
This allows us to trace through code that calls an ephemeral function,
i.e., a function that may not be alive when we are constructing the executor,
e.g. a generator expression or certain nested functions.
We will lose globals removal inside such functions,
but we can still do other peephole operations
(and even possibly [call inlining](https://github.com/python/cpython/pull/116290),
if we decide to do it), which only need the code object.
As before, if we cannot retrieve the code object from the cache, we stop projecting.
2024-03-21 16:37:41 -03:00
|
|
|
_PyFunction_ClearCodeByVersion(co->co_version);
|
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
|
|
|
}
|
2024-04-30 22:26:34 -03:00
|
|
|
#ifdef _Py_TIER2
|
2023-06-02 07:46:18 -03:00
|
|
|
if (co->co_executors != NULL) {
|
2023-06-19 06:32:20 -03:00
|
|
|
clear_executors(co);
|
2023-06-02 07:46:18 -03:00
|
|
|
}
|
2024-04-30 22:26:34 -03:00
|
|
|
#endif
|
2016-09-07 15:16:41 -03:00
|
|
|
|
2010-05-09 12:52:27 -03:00
|
|
|
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_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-05-07 11:19:19 -03:00
|
|
|
Py_XDECREF(co->co_exceptiontable);
|
2022-10-11 00:26:08 -03:00
|
|
|
if (co->_co_cached != NULL) {
|
|
|
|
Py_XDECREF(co->_co_cached->_co_code);
|
|
|
|
Py_XDECREF(co->_co_cached->_co_cellvars);
|
|
|
|
Py_XDECREF(co->_co_cached->_co_freevars);
|
|
|
|
Py_XDECREF(co->_co_cached->_co_varnames);
|
|
|
|
PyMem_Free(co->_co_cached);
|
|
|
|
}
|
2022-03-21 08:11:17 -03:00
|
|
|
if (co->co_weakreflist != NULL) {
|
2010-05-09 12:52:27 -03:00
|
|
|
PyObject_ClearWeakRefs((PyObject*)co);
|
2022-03-21 08:11:17 -03:00
|
|
|
}
|
2023-04-12 08:04:55 -03:00
|
|
|
free_monitoring_data(co->_co_monitoring);
|
2020-12-01 05:37:39 -04:00
|
|
|
PyObject_Free(co);
|
2005-10-20 16:59:25 -03:00
|
|
|
}
|
|
|
|
|
2024-04-16 13:42:53 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
static int
|
|
|
|
code_traverse(PyCodeObject *co, visitproc visit, void *arg)
|
|
|
|
{
|
|
|
|
Py_VISIT(co->co_consts);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
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;
|
2022-04-01 07:42:46 -03:00
|
|
|
eq = Py_SIZE(co) == Py_SIZE(cp);
|
|
|
|
if (!eq) {
|
2022-03-21 08:11:17 -03:00
|
|
|
goto unequal;
|
|
|
|
}
|
2022-04-01 07:42:46 -03:00
|
|
|
for (int i = 0; i < Py_SIZE(co); i++) {
|
|
|
|
_Py_CODEUNIT co_instr = _PyCode_CODE(co)[i];
|
|
|
|
_Py_CODEUNIT cp_instr = _PyCode_CODE(cp)[i];
|
2023-09-08 22:24:49 -03:00
|
|
|
uint8_t co_code = _Py_GetBaseOpcode(co, i);
|
2023-08-21 18:22:18 -03:00
|
|
|
uint8_t co_arg = co_instr.op.arg;
|
2023-09-08 22:24:49 -03:00
|
|
|
uint8_t cp_code = _Py_GetBaseOpcode(cp, i);
|
2023-08-21 18:22:18 -03:00
|
|
|
uint8_t cp_arg = cp_instr.op.arg;
|
2023-08-21 02:50:09 -03:00
|
|
|
|
2023-08-21 18:22:18 -03:00
|
|
|
if (co_code == ENTER_EXECUTOR) {
|
|
|
|
const int exec_index = co_arg;
|
2023-08-21 02:50:09 -03:00
|
|
|
_PyExecutorObject *exec = co->co_executors->executors[exec_index];
|
2023-09-08 22:24:49 -03:00
|
|
|
co_code = _PyOpcode_Deopt[exec->vm_data.opcode];
|
2023-08-21 18:22:18 -03:00
|
|
|
co_arg = exec->vm_data.oparg;
|
2023-08-21 02:50:09 -03:00
|
|
|
}
|
2023-08-21 18:22:18 -03:00
|
|
|
assert(co_code != ENTER_EXECUTOR);
|
2023-08-21 02:50:09 -03:00
|
|
|
|
2023-08-21 18:22:18 -03:00
|
|
|
if (cp_code == ENTER_EXECUTOR) {
|
|
|
|
const int exec_index = cp_arg;
|
2023-08-21 02:50:09 -03:00
|
|
|
_PyExecutorObject *exec = cp->co_executors->executors[exec_index];
|
2023-09-08 22:24:49 -03:00
|
|
|
cp_code = _PyOpcode_Deopt[exec->vm_data.opcode];
|
2023-08-21 18:22:18 -03:00
|
|
|
cp_arg = exec->vm_data.oparg;
|
2023-08-21 02:50:09 -03:00
|
|
|
}
|
2023-08-21 18:22:18 -03:00
|
|
|
assert(cp_code != ENTER_EXECUTOR);
|
2023-08-21 02:50:09 -03:00
|
|
|
|
2023-08-21 18:22:18 -03:00
|
|
|
if (co_code != cp_code || co_arg != cp_arg) {
|
2022-04-01 07:42:46 -03:00
|
|
|
goto unequal;
|
|
|
|
}
|
2023-08-21 18:22:18 -03:00
|
|
|
i += _PyOpcode_Caches[co_code];
|
2022-04-01 07:42:46 -03:00
|
|
|
}
|
2021-05-19 19:44:56 -03:00
|
|
|
|
|
|
|
/* 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;
|
2022-08-01 15:02:56 -03:00
|
|
|
eq = PyObject_RichCompareBool(co->co_linetable, cp->co_linetable, Py_EQ);
|
|
|
|
if (eq <= 0) {
|
|
|
|
goto unequal;
|
|
|
|
}
|
|
|
|
eq = PyObject_RichCompareBool(co->co_exceptiontable,
|
|
|
|
cp->co_exceptiontable, Py_EQ);
|
|
|
|
if (eq <= 0) {
|
|
|
|
goto unequal;
|
|
|
|
}
|
2021-05-19 19:44:56 -03:00
|
|
|
|
|
|
|
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:
|
2022-11-10 11:27:32 -04:00
|
|
|
return Py_NewRef(res);
|
2021-05-19 19:44:56 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static Py_hash_t
|
|
|
|
code_hash(PyCodeObject *co)
|
|
|
|
{
|
2022-12-23 14:15:47 -04:00
|
|
|
Py_uhash_t uhash = 20221211;
|
|
|
|
#define SCRAMBLE_IN(H) do { \
|
|
|
|
uhash ^= (Py_uhash_t)(H); \
|
2024-05-21 14:51:51 -03:00
|
|
|
uhash *= PyHASH_MULTIPLIER; \
|
2022-12-23 14:15:47 -04:00
|
|
|
} while (0)
|
|
|
|
#define SCRAMBLE_IN_HASH(EXPR) do { \
|
|
|
|
Py_hash_t h = PyObject_Hash(EXPR); \
|
|
|
|
if (h == -1) { \
|
|
|
|
return -1; \
|
|
|
|
} \
|
|
|
|
SCRAMBLE_IN(h); \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
SCRAMBLE_IN_HASH(co->co_name);
|
|
|
|
SCRAMBLE_IN_HASH(co->co_consts);
|
|
|
|
SCRAMBLE_IN_HASH(co->co_names);
|
|
|
|
SCRAMBLE_IN_HASH(co->co_localsplusnames);
|
|
|
|
SCRAMBLE_IN_HASH(co->co_linetable);
|
|
|
|
SCRAMBLE_IN_HASH(co->co_exceptiontable);
|
|
|
|
SCRAMBLE_IN(co->co_argcount);
|
|
|
|
SCRAMBLE_IN(co->co_posonlyargcount);
|
|
|
|
SCRAMBLE_IN(co->co_kwonlyargcount);
|
|
|
|
SCRAMBLE_IN(co->co_flags);
|
|
|
|
SCRAMBLE_IN(co->co_firstlineno);
|
|
|
|
SCRAMBLE_IN(Py_SIZE(co));
|
|
|
|
for (int i = 0; i < Py_SIZE(co); i++) {
|
2023-08-21 18:22:18 -03:00
|
|
|
_Py_CODEUNIT co_instr = _PyCode_CODE(co)[i];
|
|
|
|
uint8_t co_code = co_instr.op.code;
|
|
|
|
uint8_t co_arg = co_instr.op.arg;
|
|
|
|
if (co_code == ENTER_EXECUTOR) {
|
|
|
|
_PyExecutorObject *exec = co->co_executors->executors[co_arg];
|
|
|
|
assert(exec != NULL);
|
|
|
|
assert(exec->vm_data.opcode != ENTER_EXECUTOR);
|
|
|
|
co_code = _PyOpcode_Deopt[exec->vm_data.opcode];
|
|
|
|
co_arg = exec->vm_data.oparg;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
co_code = _Py_GetBaseOpcode(co, i);
|
|
|
|
}
|
|
|
|
SCRAMBLE_IN(co_code);
|
|
|
|
SCRAMBLE_IN(co_arg);
|
|
|
|
i += _PyOpcode_Caches[co_code];
|
2022-08-01 15:02:56 -03:00
|
|
|
}
|
2022-12-23 14:15:47 -04:00
|
|
|
if ((Py_hash_t)uhash == -1) {
|
|
|
|
return -2;
|
2022-08-01 15:02:56 -03:00
|
|
|
}
|
2022-12-23 14:15:47 -04:00
|
|
|
return (Py_hash_t)uhash;
|
2021-05-19 19:44:56 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define OFF(x) offsetof(PyCodeObject, x)
|
|
|
|
|
|
|
|
static PyMemberDef code_memberlist[] = {
|
2023-07-25 10:28:30 -03:00
|
|
|
{"co_argcount", Py_T_INT, OFF(co_argcount), Py_READONLY},
|
|
|
|
{"co_posonlyargcount", Py_T_INT, OFF(co_posonlyargcount), Py_READONLY},
|
|
|
|
{"co_kwonlyargcount", Py_T_INT, OFF(co_kwonlyargcount), Py_READONLY},
|
|
|
|
{"co_stacksize", Py_T_INT, OFF(co_stacksize), Py_READONLY},
|
|
|
|
{"co_flags", Py_T_INT, OFF(co_flags), Py_READONLY},
|
|
|
|
{"co_nlocals", Py_T_INT, OFF(co_nlocals), Py_READONLY},
|
|
|
|
{"co_consts", _Py_T_OBJECT, OFF(co_consts), Py_READONLY},
|
|
|
|
{"co_names", _Py_T_OBJECT, OFF(co_names), Py_READONLY},
|
|
|
|
{"co_filename", _Py_T_OBJECT, OFF(co_filename), Py_READONLY},
|
|
|
|
{"co_name", _Py_T_OBJECT, OFF(co_name), Py_READONLY},
|
|
|
|
{"co_qualname", _Py_T_OBJECT, OFF(co_qualname), Py_READONLY},
|
|
|
|
{"co_firstlineno", Py_T_INT, OFF(co_firstlineno), Py_READONLY},
|
|
|
|
{"co_linetable", _Py_T_OBJECT, OFF(co_linetable), Py_READONLY},
|
|
|
|
{"co_exceptiontable", _Py_T_OBJECT, OFF(co_exceptiontable), Py_READONLY},
|
2021-05-19 19:44:56 -03:00
|
|
|
{NULL} /* Sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_getlnotab(PyCodeObject *code, void *closure)
|
|
|
|
{
|
2023-04-03 12:35:04 -03:00
|
|
|
if (PyErr_WarnEx(PyExc_DeprecationWarning,
|
|
|
|
"co_lnotab is deprecated, use co_lines instead.",
|
|
|
|
1) < 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2021-05-19 19:44:56 -03:00
|
|
|
return decode_linetable(code);
|
|
|
|
}
|
|
|
|
|
2021-06-07 15:22:26 -03:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-02-24 08:10:53 -04:00
|
|
|
static PyObject *
|
2022-03-21 08:11:17 -03:00
|
|
|
code_getcodeadaptive(PyCodeObject *code, void *closure)
|
2022-02-24 08:10:53 -04:00
|
|
|
{
|
2022-04-01 08:28:50 -03:00
|
|
|
return PyBytes_FromStringAndSize(code->co_code_adaptive,
|
|
|
|
_PyCode_NBYTES(code));
|
2022-03-21 08:11:17 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_getcode(PyCodeObject *code, void *closure)
|
|
|
|
{
|
|
|
|
return _PyCode_GetCode(code);
|
2022-02-24 08:10:53 -04:00
|
|
|
}
|
|
|
|
|
2021-05-19 19:44:56 -03:00
|
|
|
static PyGetSetDef code_getsetlist[] = {
|
2022-03-21 08:11:17 -03:00
|
|
|
{"co_lnotab", (getter)code_getlnotab, NULL, NULL},
|
|
|
|
{"_co_code_adaptive", (getter)code_getcodeadaptive, NULL, NULL},
|
2021-06-07 15:22:26 -03:00
|
|
|
// The following old names are kept for backward compatibility.
|
2022-03-21 08:11:17 -03:00
|
|
|
{"co_varnames", (getter)code_getvarnames, NULL, NULL},
|
|
|
|
{"co_cellvars", (getter)code_getcellvars, NULL, NULL},
|
|
|
|
{"co_freevars", (getter)code_getfreevars, NULL, NULL},
|
|
|
|
{"co_code", (getter)code_getcode, NULL, NULL},
|
2021-05-19 19:44:56 -03:00
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
code_sizeof(PyCodeObject *co, PyObject *Py_UNUSED(args))
|
|
|
|
{
|
2022-11-29 07:15:21 -04:00
|
|
|
size_t res = _PyObject_VAR_SIZE(Py_TYPE(co), Py_SIZE(co));
|
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) {
|
2022-11-29 07:15:21 -04:00
|
|
|
res += sizeof(_PyCodeObjectExtra);
|
|
|
|
res += ((size_t)co_extra->ce_size - 1) * sizeof(co_extra->ce_extras[0]);
|
2021-06-04 13:51:05 -03:00
|
|
|
}
|
2022-11-29 07:15:21 -04:00
|
|
|
return PyLong_FromSize_t(res);
|
2012-07-26 17:23:23 -03:00
|
|
|
}
|
|
|
|
|
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]
|
2023-08-07 17:34:53 -03:00
|
|
|
@text_signature "($self, /, **changes)"
|
2019-05-24 18:57:23 -03:00
|
|
|
code.replace
|
|
|
|
|
|
|
|
*
|
2023-08-07 17:34:53 -03:00
|
|
|
co_argcount: int(c_default="self->co_argcount") = unchanged
|
|
|
|
co_posonlyargcount: int(c_default="self->co_posonlyargcount") = unchanged
|
|
|
|
co_kwonlyargcount: int(c_default="self->co_kwonlyargcount") = unchanged
|
|
|
|
co_nlocals: int(c_default="self->co_nlocals") = unchanged
|
|
|
|
co_stacksize: int(c_default="self->co_stacksize") = unchanged
|
|
|
|
co_flags: int(c_default="self->co_flags") = unchanged
|
|
|
|
co_firstlineno: int(c_default="self->co_firstlineno") = unchanged
|
|
|
|
co_code: object(subclass_of="&PyBytes_Type", c_default="NULL") = unchanged
|
|
|
|
co_consts: object(subclass_of="&PyTuple_Type", c_default="self->co_consts") = unchanged
|
|
|
|
co_names: object(subclass_of="&PyTuple_Type", c_default="self->co_names") = unchanged
|
|
|
|
co_varnames: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged
|
|
|
|
co_freevars: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged
|
|
|
|
co_cellvars: object(subclass_of="&PyTuple_Type", c_default="NULL") = unchanged
|
|
|
|
co_filename: unicode(c_default="self->co_filename") = unchanged
|
|
|
|
co_name: unicode(c_default="self->co_name") = unchanged
|
|
|
|
co_qualname: unicode(c_default="self->co_qualname") = unchanged
|
|
|
|
co_linetable: object(subclass_of="&PyBytes_Type", c_default="self->co_linetable") = unchanged
|
|
|
|
co_exceptiontable: object(subclass_of="&PyBytes_Type", c_default="self->co_exceptiontable") = unchanged
|
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,
|
2023-08-07 17:34:53 -03:00
|
|
|
int co_firstlineno, PyObject *co_code, PyObject *co_consts,
|
|
|
|
PyObject *co_names, PyObject *co_varnames,
|
|
|
|
PyObject *co_freevars, PyObject *co_cellvars,
|
|
|
|
PyObject *co_filename, PyObject *co_name,
|
|
|
|
PyObject *co_qualname, PyObject *co_linetable,
|
|
|
|
PyObject *co_exceptiontable)
|
|
|
|
/*[clinic end generated code: output=e75c48a15def18b9 input=18e280e07846c122]*/
|
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
|
|
|
|
|
2022-03-21 08:11:17 -03:00
|
|
|
PyObject *code = NULL;
|
|
|
|
if (co_code == NULL) {
|
|
|
|
code = _PyCode_GetCode(self);
|
|
|
|
if (code == NULL) {
|
|
|
|
return NULL;
|
|
|
|
}
|
2023-08-07 17:34:53 -03:00
|
|
|
co_code = code;
|
2022-03-21 08:11:17 -03:00
|
|
|
}
|
|
|
|
|
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) {
|
2023-06-29 11:22:15 -03:00
|
|
|
Py_XDECREF(code);
|
2019-11-26 20:27:50 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
co = PyCode_NewWithPosOnlyArgs(
|
2019-05-24 18:57:23 -03:00
|
|
|
co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals,
|
2023-08-07 17:34:53 -03:00
|
|
|
co_stacksize, co_flags, co_code, co_consts, co_names,
|
2019-05-24 18:57:23 -03:00
|
|
|
co_varnames, co_freevars, co_cellvars, co_filename, co_name,
|
2022-04-21 12:10:37 -03:00
|
|
|
co_qualname, co_firstlineno,
|
2023-08-07 17:34:53 -03:00
|
|
|
co_linetable, co_exceptiontable);
|
2021-06-07 15:22:26 -03:00
|
|
|
|
|
|
|
error:
|
2022-03-21 08:11:17 -03:00
|
|
|
Py_XDECREF(code);
|
2021-06-07 15:22:26 -03:00
|
|
|
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;
|
|
|
|
}
|
2022-11-10 11:27:32 -04:00
|
|
|
return Py_NewRef(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
|
2024-04-12 05:46:20 -03:00
|
|
|
{"__replace__", _PyCFunction_CAST(code_replace), METH_FASTCALL|METH_KEYWORDS,
|
|
|
|
PyDoc_STR("__replace__($self, /, **changes)\n--\n\nThe same as replace().")},
|
2021-05-19 19:44:56 -03:00
|
|
|
{NULL, NULL} /* sentinel */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
PyTypeObject PyCode_Type = {
|
|
|
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
|
|
|
"code",
|
2022-03-21 08:11:17 -03:00
|
|
|
offsetof(PyCodeObject, co_code_adaptive),
|
|
|
|
sizeof(_Py_CODEUNIT),
|
2021-05-19 19:44:56 -03:00
|
|
|
(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 */
|
2024-04-16 13:42:53 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
|
|
|
#else
|
2021-05-19 19:44:56 -03:00
|
|
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
2024-04-16 13:42:53 -03:00
|
|
|
#endif
|
2021-05-19 19:44:56 -03:00
|
|
|
code_new__doc__, /* tp_doc */
|
2024-04-16 13:42:53 -03:00
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
(traverseproc)code_traverse, /* tp_traverse */
|
|
|
|
#else
|
2021-05-19 19:44:56 -03:00
|
|
|
0, /* tp_traverse */
|
2024-04-16 13:42:53 -03:00
|
|
|
#endif
|
2021-05-19 19:44:56 -03:00
|
|
|
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. */
|
2022-11-10 11:27:32 -04:00
|
|
|
key = Py_NewRef(op);
|
2018-04-19 02:28:04 -03:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
2024-05-06 21:12:39 -03:00
|
|
|
|
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
static PyObject *
|
|
|
|
intern_one_constant(PyObject *op)
|
|
|
|
{
|
|
|
|
PyInterpreterState *interp = _PyInterpreterState_GET();
|
|
|
|
_Py_hashtable_t *consts = interp->code_state.constants;
|
|
|
|
|
|
|
|
assert(!PyUnicode_CheckExact(op)); // strings are interned separately
|
|
|
|
|
|
|
|
_Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(consts, op);
|
|
|
|
if (entry == NULL) {
|
|
|
|
if (_Py_hashtable_set(consts, op, op) != 0) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef Py_REF_DEBUG
|
|
|
|
Py_ssize_t refcnt = Py_REFCNT(op);
|
|
|
|
if (refcnt != 1) {
|
|
|
|
// Adjust the reftotal to account for the fact that we only
|
|
|
|
// restore a single reference in _PyCode_Fini.
|
|
|
|
_Py_AddRefTotal(_PyThreadState_GET(), -(refcnt - 1));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
_Py_SetImmortal(op);
|
|
|
|
return op;
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(_Py_IsImmortal(entry->value));
|
|
|
|
return (PyObject *)entry->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
compare_constants(const void *key1, const void *key2) {
|
|
|
|
PyObject *op1 = (PyObject *)key1;
|
|
|
|
PyObject *op2 = (PyObject *)key2;
|
|
|
|
if (op1 == op2) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (Py_TYPE(op1) != Py_TYPE(op2)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// We compare container contents by identity because we have already
|
|
|
|
// internalized the items.
|
|
|
|
if (PyTuple_CheckExact(op1)) {
|
|
|
|
Py_ssize_t size = PyTuple_GET_SIZE(op1);
|
|
|
|
if (size != PyTuple_GET_SIZE(op2)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
for (Py_ssize_t i = 0; i < size; i++) {
|
|
|
|
if (PyTuple_GET_ITEM(op1, i) != PyTuple_GET_ITEM(op2, i)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else if (PyFrozenSet_CheckExact(op1)) {
|
|
|
|
if (PySet_GET_SIZE(op1) != PySet_GET_SIZE(op2)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
Py_ssize_t pos1 = 0, pos2 = 0;
|
|
|
|
PyObject *obj1, *obj2;
|
|
|
|
Py_hash_t hash1, hash2;
|
|
|
|
while ((_PySet_NextEntry(op1, &pos1, &obj1, &hash1)) &&
|
|
|
|
(_PySet_NextEntry(op2, &pos2, &obj2, &hash2)))
|
|
|
|
{
|
|
|
|
if (obj1 != obj2) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else if (PySlice_Check(op1)) {
|
|
|
|
PySliceObject *s1 = (PySliceObject *)op1;
|
|
|
|
PySliceObject *s2 = (PySliceObject *)op2;
|
|
|
|
return (s1->start == s2->start &&
|
|
|
|
s1->stop == s2->stop &&
|
|
|
|
s1->step == s2->step);
|
|
|
|
}
|
|
|
|
else if (PyBytes_CheckExact(op1) || PyLong_CheckExact(op1)) {
|
|
|
|
return PyObject_RichCompareBool(op1, op2, Py_EQ);
|
|
|
|
}
|
|
|
|
else if (PyFloat_CheckExact(op1)) {
|
|
|
|
// Ensure that, for example, +0.0 and -0.0 are distinct
|
|
|
|
double f1 = PyFloat_AS_DOUBLE(op1);
|
|
|
|
double f2 = PyFloat_AS_DOUBLE(op2);
|
|
|
|
return memcmp(&f1, &f2, sizeof(double)) == 0;
|
|
|
|
}
|
|
|
|
else if (PyComplex_CheckExact(op1)) {
|
|
|
|
Py_complex c1 = ((PyComplexObject *)op1)->cval;
|
|
|
|
Py_complex c2 = ((PyComplexObject *)op2)->cval;
|
|
|
|
return memcmp(&c1, &c2, sizeof(Py_complex)) == 0;
|
|
|
|
}
|
|
|
|
_Py_FatalErrorFormat("unexpected type in compare_constants: %s",
|
|
|
|
Py_TYPE(op1)->tp_name);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Py_uhash_t
|
|
|
|
hash_const(const void *key)
|
|
|
|
{
|
|
|
|
PyObject *op = (PyObject *)key;
|
|
|
|
if (PySlice_Check(op)) {
|
|
|
|
PySliceObject *s = (PySliceObject *)op;
|
|
|
|
PyObject *data[3] = { s->start, s->stop, s->step };
|
|
|
|
return _Py_HashBytes(&data, sizeof(data));
|
|
|
|
}
|
|
|
|
else if (PyTuple_CheckExact(op)) {
|
|
|
|
Py_ssize_t size = PyTuple_GET_SIZE(op);
|
|
|
|
PyObject **data = _PyTuple_ITEMS(op);
|
|
|
|
return _Py_HashBytes(data, sizeof(PyObject *) * size);
|
|
|
|
}
|
|
|
|
Py_hash_t h = PyObject_Hash(op);
|
|
|
|
if (h == -1) {
|
|
|
|
// This should never happen: all the constants we support have
|
|
|
|
// infallible hash functions.
|
|
|
|
Py_FatalError("code: hash failed");
|
|
|
|
}
|
|
|
|
return (Py_uhash_t)h;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
clear_containers(_Py_hashtable_t *ht, const void *key, const void *value,
|
|
|
|
void *user_data)
|
|
|
|
{
|
|
|
|
// First clear containers to avoid recursive deallocation later on in
|
|
|
|
// destroy_key.
|
|
|
|
PyObject *op = (PyObject *)key;
|
|
|
|
if (PyTuple_CheckExact(op)) {
|
|
|
|
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(op); i++) {
|
|
|
|
Py_CLEAR(_PyTuple_ITEMS(op)[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (PySlice_Check(op)) {
|
|
|
|
PySliceObject *slice = (PySliceObject *)op;
|
|
|
|
Py_SETREF(slice->start, Py_None);
|
|
|
|
Py_SETREF(slice->stop, Py_None);
|
|
|
|
Py_SETREF(slice->step, Py_None);
|
|
|
|
}
|
|
|
|
else if (PyFrozenSet_CheckExact(op)) {
|
|
|
|
_PySet_ClearInternal((PySetObject *)op);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
destroy_key(void *key)
|
|
|
|
{
|
|
|
|
_Py_ClearImmortal(key);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
PyStatus
|
|
|
|
_PyCode_Init(PyInterpreterState *interp)
|
|
|
|
{
|
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
struct _py_code_state *state = &interp->code_state;
|
|
|
|
state->constants = _Py_hashtable_new_full(&hash_const, &compare_constants,
|
|
|
|
&destroy_key, NULL, NULL);
|
|
|
|
if (state->constants == NULL) {
|
|
|
|
return _PyStatus_NO_MEMORY();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return _PyStatus_OK();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
_PyCode_Fini(PyInterpreterState *interp)
|
|
|
|
{
|
|
|
|
#ifdef Py_GIL_DISABLED
|
|
|
|
// Free interned constants
|
|
|
|
struct _py_code_state *state = &interp->code_state;
|
|
|
|
if (state->constants) {
|
|
|
|
_Py_hashtable_foreach(state->constants, &clear_containers, NULL);
|
|
|
|
_Py_hashtable_destroy(state->constants);
|
|
|
|
state->constants = NULL;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|