aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Objects/codeobject.c
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.com>2024-02-12 07:53:52 +0300
committerDaniil Cherednik <dcherednik@ydb.tech>2024-02-14 14:26:16 +0000
commit31f2a419764a8ba77c2a970cfc80056c6cd06756 (patch)
treec1995d239eba8571cefc640f6648e1d5dd4ce9e2 /contrib/tools/python3/src/Objects/codeobject.c
parentfe2ef02b38d9c85d80060963b265a1df9f38c3bb (diff)
downloadydb-31f2a419764a8ba77c2a970cfc80056c6cd06756.tar.gz
Update Python from 3.11.8 to 3.12.2
Diffstat (limited to 'contrib/tools/python3/src/Objects/codeobject.c')
-rw-r--r--contrib/tools/python3/src/Objects/codeobject.c653
1 files changed, 422 insertions, 231 deletions
diff --git a/contrib/tools/python3/src/Objects/codeobject.c b/contrib/tools/python3/src/Objects/codeobject.c
index 5881711724..5e358825d8 100644
--- a/contrib/tools/python3/src/Objects/codeobject.c
+++ b/contrib/tools/python3/src/Objects/codeobject.c
@@ -4,12 +4,108 @@
#include "opcode.h"
#include "structmember.h" // PyMemberDef
#include "pycore_code.h" // _PyCodeConstructor
+#include "pycore_frame.h" // FRAME_SPECIALS_SIZE
#include "pycore_interp.h" // PyInterpreterState.co_extra_freefuncs
#include "pycore_opcode.h" // _PyOpcode_Deopt
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "clinic/codeobject.c.h"
+static PyObject* code_repr(PyCodeObject *co);
+
+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();
+}
+
+static void
+notify_code_watchers(PyCodeEvent event, PyCodeObject *co)
+{
+ assert(Py_REFCNT(co) > 0);
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ assert(interp->_initialized);
+ uint8_t bits = interp->active_code_watchers;
+ int i = 0;
+ while (bits) {
+ assert(i < CODE_MAX_WATCHERS);
+ if (bits & 1) {
+ PyCode_WatchCallback cb = interp->code_watchers[i];
+ // callback must be non-null if the watcher bit is set
+ assert(cb != NULL);
+ if (cb(event, co) < 0) {
+ // Don't risk resurrecting the object if an unraisablehook keeps
+ // a reference; pass a string as context.
+ PyObject *context = NULL;
+ PyObject *repr = code_repr(co);
+ if (repr) {
+ context = PyUnicode_FromFormat(
+ "%s watcher callback for %U",
+ code_event_name(event), repr);
+ Py_DECREF(repr);
+ }
+ if (context == NULL) {
+ context = Py_NewRef(Py_None);
+ }
+ PyErr_WriteUnraisable(context);
+ Py_DECREF(context);
+ }
+ }
+ i++;
+ bits >>= 1;
+ }
+}
+
+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;
+}
/******************
* generic helpers
@@ -149,7 +245,22 @@ validate_and_copy_tuple(PyObject *tup)
return newtuple;
}
+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;
+}
/******************
* _PyCode_New()
******************/
@@ -159,18 +270,16 @@ void
_Py_set_localsplus_info(int offset, PyObject *name, _PyLocals_Kind kind,
PyObject *names, PyObject *kinds)
{
- Py_INCREF(name);
- PyTuple_SET_ITEM(names, offset, name);
+ PyTuple_SET_ITEM(names, offset, Py_NewRef(name));
_PyLocals_SetKind(kinds, offset, kind);
}
static void
get_localsplus_counts(PyObject *names, PyObject *kinds,
- int *pnlocals, int *pnplaincellvars, int *pncellvars,
+ int *pnlocals, int *pncellvars,
int *pnfreevars)
{
int nlocals = 0;
- int nplaincellvars = 0;
int ncellvars = 0;
int nfreevars = 0;
Py_ssize_t nlocalsplus = PyTuple_GET_SIZE(names);
@@ -184,7 +293,6 @@ get_localsplus_counts(PyObject *names, PyObject *kinds,
}
else if (kind & CO_FAST_CELL) {
ncellvars += 1;
- nplaincellvars += 1;
}
else if (kind & CO_FAST_FREE) {
nfreevars += 1;
@@ -193,9 +301,6 @@ get_localsplus_counts(PyObject *names, PyObject *kinds,
if (pnlocals != NULL) {
*pnlocals = nlocals;
}
- if (pnplaincellvars != NULL) {
- *pnplaincellvars = nplaincellvars;
- }
if (pncellvars != NULL) {
*pncellvars = ncellvars;
}
@@ -219,8 +324,7 @@ get_localsplus_names(PyCodeObject *co, _PyLocals_Kind kind, int num)
}
assert(index < num);
PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, offset);
- Py_INCREF(name);
- PyTuple_SET_ITEM(names, index, name);
+ PyTuple_SET_ITEM(names, index, Py_NewRef(name));
index += 1;
}
assert(index == num);
@@ -271,7 +375,7 @@ _PyCode_Validate(struct _PyCodeConstructor *con)
* here to avoid the possibility of overflow (however remote). */
int nlocals;
get_localsplus_counts(con->localsplusnames, con->localspluskinds,
- &nlocals, NULL, NULL, NULL);
+ &nlocals, NULL, NULL);
int nplainlocals = nlocals -
con->argcount -
con->kwonlyargcount -
@@ -285,35 +389,29 @@ _PyCode_Validate(struct _PyCodeConstructor *con)
return 0;
}
+extern void _PyCode_Quicken(PyCodeObject *code);
+
static void
init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
{
int nlocalsplus = (int)PyTuple_GET_SIZE(con->localsplusnames);
- int nlocals, nplaincellvars, ncellvars, nfreevars;
+ int nlocals, ncellvars, nfreevars;
get_localsplus_counts(con->localsplusnames, con->localspluskinds,
- &nlocals, &nplaincellvars, &ncellvars, &nfreevars);
-
- Py_INCREF(con->filename);
- co->co_filename = con->filename;
- Py_INCREF(con->name);
- co->co_name = con->name;
- Py_INCREF(con->qualname);
- co->co_qualname = con->qualname;
+ &nlocals, &ncellvars, &nfreevars);
+
+ co->co_filename = Py_NewRef(con->filename);
+ co->co_name = Py_NewRef(con->name);
+ co->co_qualname = Py_NewRef(con->qualname);
co->co_flags = con->flags;
co->co_firstlineno = con->firstlineno;
- Py_INCREF(con->linetable);
- co->co_linetable = con->linetable;
+ co->co_linetable = Py_NewRef(con->linetable);
- Py_INCREF(con->consts);
- co->co_consts = con->consts;
- Py_INCREF(con->names);
- co->co_names = con->names;
+ co->co_consts = Py_NewRef(con->consts);
+ co->co_names = Py_NewRef(con->names);
- Py_INCREF(con->localsplusnames);
- co->co_localsplusnames = con->localsplusnames;
- Py_INCREF(con->localspluskinds);
- co->co_localspluskinds = con->localspluskinds;
+ co->co_localsplusnames = Py_NewRef(con->localsplusnames);
+ co->co_localspluskinds = Py_NewRef(con->localspluskinds);
co->co_argcount = con->argcount;
co->co_posonlyargcount = con->posonlyargcount;
@@ -321,32 +419,35 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
co->co_stacksize = con->stacksize;
- Py_INCREF(con->exceptiontable);
- co->co_exceptiontable = con->exceptiontable;
+ co->co_exceptiontable = Py_NewRef(con->exceptiontable);
/* derived values */
co->co_nlocalsplus = nlocalsplus;
co->co_nlocals = nlocals;
- co->co_nplaincellvars = nplaincellvars;
+ co->co_framesize = nlocalsplus + con->stacksize + FRAME_SPECIALS_SIZE;
co->co_ncellvars = ncellvars;
co->co_nfreevars = nfreevars;
-
+ co->co_version = _Py_next_func_version;
+ if (_Py_next_func_version != 0) {
+ _Py_next_func_version++;
+ }
+ co->_co_monitoring = NULL;
+ co->_co_instrumentation_version = 0;
/* not set */
co->co_weakreflist = NULL;
co->co_extra = NULL;
- co->_co_code = NULL;
+ co->_co_cached = NULL;
- co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
- co->_co_linearray_entry_size = 0;
- co->_co_linearray = NULL;
memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code),
PyBytes_GET_SIZE(con->code));
int entry_point = 0;
while (entry_point < Py_SIZE(co) &&
- _Py_OPCODE(_PyCode_CODE(co)[entry_point]) != RESUME) {
+ _PyCode_CODE(co)[entry_point].op.code != RESUME) {
entry_point++;
}
co->_co_firsttraceable = entry_point;
+ _PyCode_Quicken(co);
+ notify_code_watchers(PY_CODE_EVENT_CREATE, co);
}
static int
@@ -495,7 +596,8 @@ _PyCode_New(struct _PyCodeConstructor *con)
******************/
PyCodeObject *
-PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
+PyUnstable_Code_NewWithPosOnlyArgs(
+ int argcount, int posonlyargcount, int kwonlyargcount,
int nlocals, int stacksize, int flags,
PyObject *code, PyObject *consts, PyObject *names,
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
@@ -563,6 +665,35 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount,
_Py_set_localsplus_info(offset, name, CO_FAST_FREE,
localsplusnames, localspluskinds);
}
+
+ // 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;
+ }
+ }
+
// If any cells were args then nlocalsplus will have shrunk.
if (nlocalsplus != PyTuple_GET_SIZE(localsplusnames)) {
if (_PyTuple_Resize(&localsplusnames, nlocalsplus) < 0
@@ -619,7 +750,7 @@ error:
}
PyCodeObject *
-PyCode_New(int argcount, int kwonlyargcount,
+PyUnstable_Code_New(int argcount, int kwonlyargcount,
int nlocals, int stacksize, int flags,
PyObject *code, PyObject *consts, PyObject *names,
PyObject *varnames, PyObject *freevars, PyObject *cellvars,
@@ -714,54 +845,6 @@ failed:
* source location tracking (co_lines/co_positions)
******************/
-/* Use co_linetable to compute the line number from a bytecode index, addrq. See
- lnotab_notes.txt for the details of the lnotab representation.
-*/
-
-int
-_PyCode_CreateLineArray(PyCodeObject *co)
-{
- assert(co->_co_linearray == NULL);
- PyCodeAddressRange bounds;
- int size;
- int max_line = 0;
- _PyCode_InitAddressRange(co, &bounds);
- while(_PyLineTable_NextAddressRange(&bounds)) {
- if (bounds.ar_line > max_line) {
- max_line = bounds.ar_line;
- }
- }
- if (max_line < (1 << 15)) {
- size = 2;
- }
- else {
- size = 4;
- }
- co->_co_linearray = PyMem_Malloc(Py_SIZE(co)*size);
- if (co->_co_linearray == NULL) {
- PyErr_NoMemory();
- return -1;
- }
- co->_co_linearray_entry_size = size;
- _PyCode_InitAddressRange(co, &bounds);
- while(_PyLineTable_NextAddressRange(&bounds)) {
- int start = bounds.ar_start / sizeof(_Py_CODEUNIT);
- int end = bounds.ar_end / sizeof(_Py_CODEUNIT);
- for (int index = start; index < end; index++) {
- assert(index < (int)Py_SIZE(co));
- if (size == 2) {
- assert(((int16_t)bounds.ar_line) == bounds.ar_line);
- ((int16_t *)co->_co_linearray)[index] = bounds.ar_line;
- }
- else {
- assert(size == 4);
- ((int32_t *)co->_co_linearray)[index] = bounds.ar_line;
- }
- }
- }
- return 0;
-}
-
int
PyCode_Addr2Line(PyCodeObject *co, int addrq)
{
@@ -769,9 +852,6 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq)
return co->co_firstlineno;
}
assert(addrq >= 0 && addrq <= _PyCode_NBYTES(co));
- if (co->_co_linearray) {
- return _PyCode_LineNumberFromArray(co, addrq / sizeof(_Py_CODEUNIT));
- }
PyCodeAddressRange bounds;
_PyCode_InitAddressRange(co, &bounds);
return _PyCode_CheckLineNumber(addrq, &bounds);
@@ -1025,33 +1105,6 @@ _PyLineTable_NextAddressRange(PyCodeAddressRange *range)
return 1;
}
-int
-_PyLineTable_StartsLine(PyCodeAddressRange *range)
-{
- if (range->ar_start <= 0) {
- return 0;
- }
- const uint8_t *ptr = range->opaque.lo_next;
- do {
- ptr--;
- } while (((*ptr) & 128) == 0);
- int code = ((*ptr)>> 3) & 15;
- switch(code) {
- case PY_CODE_LOCATION_INFO_LONG:
- return 0;
- case PY_CODE_LOCATION_INFO_NO_COLUMNS:
- case PY_CODE_LOCATION_INFO_NONE:
- return ptr[1] != 0;
- case PY_CODE_LOCATION_INFO_ONE_LINE0:
- return 0;
- case PY_CODE_LOCATION_INFO_ONE_LINE1:
- case PY_CODE_LOCATION_INFO_ONE_LINE2:
- return 1;
- default:
- return 0;
- }
-}
-
static int
emit_pair(PyObject **bytes, int *offset, int a, int b)
{
@@ -1139,41 +1192,34 @@ lineiter_dealloc(lineiterator *li)
}
static PyObject *
+_source_offset_converter(int *value) {
+ if (*value == -1) {
+ Py_RETURN_NONE;
+ }
+ return PyLong_FromLong(*value);
+}
+
+static PyObject *
lineiter_next(lineiterator *li)
{
PyCodeAddressRange *bounds = &li->li_line;
if (!_PyLineTable_NextAddressRange(bounds)) {
return NULL;
}
- PyObject *start = NULL;
- PyObject *end = NULL;
- PyObject *line = NULL;
- PyObject *result = PyTuple_New(3);
- start = PyLong_FromLong(bounds->ar_start);
- end = PyLong_FromLong(bounds->ar_end);
- if (bounds->ar_line < 0) {
- Py_INCREF(Py_None);
- line = Py_None;
- }
- else {
- line = PyLong_FromLong(bounds->ar_line);
- }
- if (result == NULL || start == NULL || end == NULL || line == NULL) {
- goto error;
+ 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;
+ }
}
- PyTuple_SET_ITEM(result, 0, start);
- PyTuple_SET_ITEM(result, 1, end);
- PyTuple_SET_ITEM(result, 2, line);
- return result;
-error:
- Py_XDECREF(start);
- Py_XDECREF(end);
- Py_XDECREF(line);
- Py_XDECREF(result);
- return result;
+ return Py_BuildValue("iiO&", start, bounds->ar_end,
+ _source_offset_converter, &line);
}
-static PyTypeObject LineIterator = {
+PyTypeObject _PyLineIterator = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"line_iterator", /* tp_name */
sizeof(lineiterator), /* tp_basicsize */
@@ -1219,12 +1265,11 @@ static PyTypeObject LineIterator = {
static lineiterator *
new_linesiterator(PyCodeObject *code)
{
- lineiterator *li = (lineiterator *)PyType_GenericAlloc(&LineIterator, 0);
+ lineiterator *li = (lineiterator *)PyType_GenericAlloc(&_PyLineIterator, 0);
if (li == NULL) {
return NULL;
}
- Py_INCREF(code);
- li->li_code = code;
+ li->li_code = (PyCodeObject*)Py_NewRef(code);
_PyCode_InitAddressRange(code, &li->li_line);
return li;
}
@@ -1248,14 +1293,6 @@ positionsiter_dealloc(positionsiterator* pi)
}
static PyObject*
-_source_offset_converter(int* value) {
- if (*value == -1) {
- Py_RETURN_NONE;
- }
- return PyLong_FromLong(*value);
-}
-
-static PyObject*
positionsiter_next(positionsiterator* pi)
{
if (pi->pi_offset >= pi->pi_range.ar_end) {
@@ -1273,7 +1310,7 @@ positionsiter_next(positionsiterator* pi)
_source_offset_converter, &pi->pi_endcolumn);
}
-static PyTypeObject PositionsIterator = {
+PyTypeObject _PyPositionsIterator = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"positions_iterator", /* tp_name */
sizeof(positionsiterator), /* tp_basicsize */
@@ -1319,12 +1356,11 @@ static PyTypeObject PositionsIterator = {
static PyObject*
code_positionsiterator(PyCodeObject* code, PyObject* Py_UNUSED(args))
{
- positionsiterator* pi = (positionsiterator*)PyType_GenericAlloc(&PositionsIterator, 0);
+ positionsiterator* pi = (positionsiterator*)PyType_GenericAlloc(&_PyPositionsIterator, 0);
if (pi == NULL) {
return NULL;
}
- Py_INCREF(code);
- pi->pi_code = code;
+ pi->pi_code = (PyCodeObject*)Py_NewRef(code);
_PyCode_InitAddressRange(code, &pi->pi_range);
pi->pi_offset = pi->pi_range.ar_end;
return (PyObject*)pi;
@@ -1343,7 +1379,7 @@ typedef struct {
int
-_PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
+PyUnstable_Code_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
{
if (!PyCode_Check(code)) {
PyErr_BadInternalCall();
@@ -1364,7 +1400,7 @@ _PyCode_GetExtra(PyObject *code, Py_ssize_t index, void **extra)
int
-_PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
+PyUnstable_Code_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
@@ -1409,10 +1445,31 @@ _PyCode_SetExtra(PyObject *code, Py_ssize_t index, void *extra)
* other PyCodeObject accessor functions
******************/
+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;
+}
+
PyObject *
_PyCode_GetVarnames(PyCodeObject *co)
{
- return get_localsplus_names(co, CO_FAST_LOCAL, co->co_nlocals);
+ if (init_co_cached(co)) {
+ return NULL;
+ }
+ return get_cached_locals(co, &co->_co_cached->_co_varnames, CO_FAST_LOCAL, co->co_nlocals);
}
PyObject *
@@ -1424,7 +1481,10 @@ PyCode_GetVarnames(PyCodeObject *code)
PyObject *
_PyCode_GetCellvars(PyCodeObject *co)
{
- return get_localsplus_names(co, CO_FAST_CELL, co->co_ncellvars);
+ if (init_co_cached(co)) {
+ return NULL;
+ }
+ return get_cached_locals(co, &co->_co_cached->_co_cellvars, CO_FAST_CELL, co->co_ncellvars);
}
PyObject *
@@ -1436,7 +1496,10 @@ PyCode_GetCellvars(PyCodeObject *code)
PyObject *
_PyCode_GetFreevars(PyCodeObject *co)
{
- return get_localsplus_names(co, CO_FAST_FREE, co->co_nfreevars);
+ if (init_co_cached(co)) {
+ return NULL;
+ }
+ return get_cached_locals(co, &co->_co_cached->_co_freevars, CO_FAST_FREE, co->co_nfreevars);
}
PyObject *
@@ -1446,33 +1509,37 @@ PyCode_GetFreevars(PyCodeObject *code)
}
static void
-deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
+deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions)
{
+ Py_ssize_t len = Py_SIZE(code);
for (int i = 0; i < len; i++) {
- _Py_CODEUNIT instruction = instructions[i];
- int opcode = _PyOpcode_Deopt[_Py_OPCODE(instruction)];
+ int opcode = _Py_GetBaseOpcode(code, i);
int caches = _PyOpcode_Caches[opcode];
- instructions[i] = _Py_MAKECODEUNIT(opcode, _Py_OPARG(instruction));
- while (caches--) {
- instructions[++i] = _Py_MAKECODEUNIT(CACHE, 0);
+ instructions[i].op.code = opcode;
+ for (int j = 1; j <= caches; j++) {
+ instructions[i+j].cache = 0;
}
+ i += caches;
}
}
PyObject *
_PyCode_GetCode(PyCodeObject *co)
{
- if (co->_co_code != NULL) {
- return Py_NewRef(co->_co_code);
+ if (init_co_cached(co)) {
+ return NULL;
+ }
+ if (co->_co_cached->_co_code != NULL) {
+ return Py_NewRef(co->_co_cached->_co_code);
}
PyObject *code = PyBytes_FromStringAndSize((const char *)_PyCode_CODE(co),
_PyCode_NBYTES(co));
if (code == NULL) {
return NULL;
}
- deopt_code((_Py_CODEUNIT *)PyBytes_AS_STRING(code), Py_SIZE(co));
- assert(co->_co_code == NULL);
- co->_co_code = Py_NewRef(code);
+ deopt_code(co, (_Py_CODEUNIT *)PyBytes_AS_STRING(code));
+ assert(co->_co_cached->_co_code == NULL);
+ co->_co_cached->_co_code = Py_NewRef(code);
return code;
}
@@ -1605,8 +1672,41 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount,
}
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);
+}
+
+static void
code_dealloc(PyCodeObject *co)
{
+ assert(Py_REFCNT(co) == 0);
+ Py_SET_REFCNT(co, 1);
+ notify_code_watchers(PY_CODE_EVENT_DESTROY, co);
+ if (Py_REFCNT(co) > 1) {
+ Py_SET_REFCNT(co, Py_REFCNT(co) - 1);
+ return;
+ }
+ Py_SET_REFCNT(co, 0);
+
if (co->co_extra != NULL) {
PyInterpreterState *interp = _PyInterpreterState_GET();
_PyCodeObjectExtra *co_extra = co->co_extra;
@@ -1631,16 +1731,17 @@ code_dealloc(PyCodeObject *co)
Py_XDECREF(co->co_qualname);
Py_XDECREF(co->co_linetable);
Py_XDECREF(co->co_exceptiontable);
- Py_XDECREF(co->_co_code);
+ 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);
+ }
if (co->co_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject*)co);
}
- if (co->_co_linearray) {
- PyMem_Free(co->_co_linearray);
- }
- if (co->co_warmup == 0) {
- _Py_QuickenedCount--;
- }
+ free_monitoring_data(co->_co_monitoring);
PyObject_Free(co);
}
@@ -1699,13 +1800,13 @@ code_richcompare(PyObject *self, PyObject *other, int op)
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];
- _Py_SET_OPCODE(co_instr, _PyOpcode_Deopt[_Py_OPCODE(co_instr)]);
- _Py_SET_OPCODE(cp_instr, _PyOpcode_Deopt[_Py_OPCODE(cp_instr)]);
- eq = co_instr == cp_instr;
+ co_instr.op.code = _Py_GetBaseOpcode(co, i);
+ cp_instr.op.code = _Py_GetBaseOpcode(cp, i);
+ eq = co_instr.cache == cp_instr.cache;
if (!eq) {
goto unequal;
}
- i += _PyOpcode_Caches[_Py_OPCODE(co_instr)];
+ i += _PyOpcode_Caches[co_instr.op.code];
}
/* compare constants */
@@ -1752,35 +1853,47 @@ code_richcompare(PyObject *self, PyObject *other, int op)
res = Py_False;
done:
- Py_INCREF(res);
- return res;
+ return Py_NewRef(res);
}
static Py_hash_t
code_hash(PyCodeObject *co)
{
- Py_hash_t h, h0, h1, h2, h3;
- h0 = PyObject_Hash(co->co_name);
- if (h0 == -1) return -1;
- h1 = PyObject_Hash(co->co_consts);
- if (h1 == -1) return -1;
- h2 = PyObject_Hash(co->co_names);
- if (h2 == -1) return -1;
- h3 = PyObject_Hash(co->co_localsplusnames);
- if (h3 == -1) return -1;
- Py_hash_t h4 = PyObject_Hash(co->co_linetable);
- if (h4 == -1) {
- return -1;
+ Py_uhash_t uhash = 20221211;
+ #define SCRAMBLE_IN(H) do { \
+ uhash ^= (Py_uhash_t)(H); \
+ uhash *= _PyHASH_MULTIPLIER; \
+ } 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++) {
+ int deop = _Py_GetBaseOpcode(co, i);
+ SCRAMBLE_IN(deop);
+ SCRAMBLE_IN(_PyCode_CODE(co)[i].op.arg);
+ i += _PyOpcode_Caches[deop];
}
- Py_hash_t h5 = PyObject_Hash(co->co_exceptiontable);
- if (h5 == -1) {
- return -1;
+ if ((Py_hash_t)uhash == -1) {
+ return -2;
}
- h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^
- co->co_argcount ^ co->co_posonlyargcount ^ co->co_kwonlyargcount ^
- co->co_flags;
- if (h == -1) h = -2;
- return h;
+ return (Py_hash_t)uhash;
}
@@ -1808,6 +1921,11 @@ static PyMemberDef code_memberlist[] = {
static PyObject *
code_getlnotab(PyCodeObject *code, void *closure)
{
+ if (PyErr_WarnEx(PyExc_DeprecationWarning,
+ "co_lnotab is deprecated, use co_lines instead.",
+ 1) < 0) {
+ return NULL;
+ }
return decode_linetable(code);
}
@@ -1857,15 +1975,13 @@ static PyGetSetDef code_getsetlist[] = {
static PyObject *
code_sizeof(PyCodeObject *co, PyObject *Py_UNUSED(args))
{
- Py_ssize_t res = _PyObject_VAR_SIZE(Py_TYPE(co), Py_SIZE(co));
-
+ size_t res = _PyObject_VAR_SIZE(Py_TYPE(co), Py_SIZE(co));
_PyCodeObjectExtra *co_extra = (_PyCodeObjectExtra*) co->co_extra;
if (co_extra != NULL) {
- res += sizeof(_PyCodeObjectExtra) +
- (co_extra->ce_size-1) * sizeof(co_extra->ce_extras[0]);
+ res += sizeof(_PyCodeObjectExtra);
+ res += ((size_t)co_extra->ce_size - 1) * sizeof(co_extra->ce_extras[0]);
}
-
- return PyLong_FromSsize_t(res);
+ return PyLong_FromSize_t(res);
}
static PyObject *
@@ -2006,8 +2122,7 @@ code__varname_from_oparg_impl(PyCodeObject *self, int oparg)
if (name == NULL) {
return NULL;
}
- Py_INCREF(name);
- return name;
+ return Py_NewRef(name);
}
/* XXX code objects need to participate in GC? */
@@ -2082,8 +2197,7 @@ _PyCode_ConstantKey(PyObject *op)
{
/* Objects of these types are always different from object of other
* type and from tuples. */
- Py_INCREF(op);
- key = op;
+ key = Py_NewRef(op);
}
else if (PyBool_Check(op) || PyBytes_CheckExact(op)) {
/* Make booleans different from integers 0 and 1.
@@ -2199,28 +2313,29 @@ _PyCode_ConstantKey(PyObject *op)
}
void
-_PyStaticCode_Dealloc(PyCodeObject *co)
+_PyStaticCode_Fini(PyCodeObject *co)
{
- if (co->co_warmup == 0) {
- _Py_QuickenedCount--;
- }
- deopt_code(_PyCode_CODE(co), Py_SIZE(co));
- co->co_warmup = QUICKENING_INITIAL_WARMUP_VALUE;
+ deopt_code(co, _PyCode_CODE(co));
PyMem_Free(co->co_extra);
- Py_CLEAR(co->_co_code);
+ if (co->_co_cached != NULL) {
+ Py_CLEAR(co->_co_cached->_co_code);
+ Py_CLEAR(co->_co_cached->_co_cellvars);
+ Py_CLEAR(co->_co_cached->_co_freevars);
+ Py_CLEAR(co->_co_cached->_co_varnames);
+ PyMem_Free(co->_co_cached);
+ co->_co_cached = NULL;
+ }
co->co_extra = NULL;
if (co->co_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *)co);
co->co_weakreflist = NULL;
}
- if (co->_co_linearray) {
- PyMem_Free(co->_co_linearray);
- co->_co_linearray = NULL;
- }
+ free_monitoring_data(co->_co_monitoring);
+ co->_co_monitoring = NULL;
}
int
-_PyStaticCode_InternStrings(PyCodeObject *co)
+_PyStaticCode_Init(PyCodeObject *co)
{
int res = intern_strings(co->co_names);
if (res < 0) {
@@ -2234,5 +2349,81 @@ _PyStaticCode_InternStrings(PyCodeObject *co)
if (res < 0) {
return -1;
}
+ _PyCode_Quicken(co);
return 0;
}
+
+#define MAX_CODE_UNITS_PER_LOC_ENTRY 8
+
+PyCodeObject *
+_Py_MakeShimCode(const _PyShimCodeDef *codedef)
+{
+ PyObject *name = NULL;
+ PyObject *co_code = NULL;
+ PyObject *lines = NULL;
+ PyCodeObject *codeobj = NULL;
+ uint8_t *loc_table = NULL;
+
+ name = _PyUnicode_FromASCII(codedef->cname, strlen(codedef->cname));
+ if (name == NULL) {
+ goto cleanup;
+ }
+ co_code = PyBytes_FromStringAndSize(
+ (const char *)codedef->code, codedef->codelen);
+ if (co_code == NULL) {
+ goto cleanup;
+ }
+ int code_units = codedef->codelen / sizeof(_Py_CODEUNIT);
+ int loc_entries = (code_units + MAX_CODE_UNITS_PER_LOC_ENTRY - 1) /
+ MAX_CODE_UNITS_PER_LOC_ENTRY;
+ loc_table = PyMem_Malloc(loc_entries);
+ if (loc_table == NULL) {
+ PyErr_NoMemory();
+ goto cleanup;
+ }
+ for (int i = 0; i < loc_entries-1; i++) {
+ loc_table[i] = 0x80 | (PY_CODE_LOCATION_INFO_NONE << 3) | 7;
+ code_units -= MAX_CODE_UNITS_PER_LOC_ENTRY;
+ }
+ assert(loc_entries > 0);
+ assert(code_units > 0 && code_units <= MAX_CODE_UNITS_PER_LOC_ENTRY);
+ loc_table[loc_entries-1] = 0x80 |
+ (PY_CODE_LOCATION_INFO_NONE << 3) | (code_units-1);
+ lines = PyBytes_FromStringAndSize((const char *)loc_table, loc_entries);
+ PyMem_Free(loc_table);
+ if (lines == NULL) {
+ goto cleanup;
+ }
+ _Py_DECLARE_STR(shim_name, "<shim>");
+ struct _PyCodeConstructor con = {
+ .filename = &_Py_STR(shim_name),
+ .name = name,
+ .qualname = name,
+ .flags = CO_NEWLOCALS | CO_OPTIMIZED,
+
+ .code = co_code,
+ .firstlineno = 1,
+ .linetable = lines,
+
+ .consts = (PyObject *)&_Py_SINGLETON(tuple_empty),
+ .names = (PyObject *)&_Py_SINGLETON(tuple_empty),
+
+ .localsplusnames = (PyObject *)&_Py_SINGLETON(tuple_empty),
+ .localspluskinds = (PyObject *)&_Py_SINGLETON(bytes_empty),
+
+ .argcount = 0,
+ .posonlyargcount = 0,
+ .kwonlyargcount = 0,
+
+ .stacksize = codedef->stacksize,
+
+ .exceptiontable = (PyObject *)&_Py_SINGLETON(bytes_empty),
+ };
+
+ codeobj = _PyCode_New(&con);
+cleanup:
+ Py_XDECREF(name);
+ Py_XDECREF(co_code);
+ Py_XDECREF(lines);
+ return codeobj;
+}