diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-04-18 12:39:32 +0300 |
---|---|---|
committer | shadchin <shadchin@yandex-team.ru> | 2022-04-18 12:39:32 +0300 |
commit | d4be68e361f4258cf0848fc70018dfe37a2acc24 (patch) | |
tree | 153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Objects | |
parent | 260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff) | |
download | ydb-d4be68e361f4258cf0848fc70018dfe37a2acc24.tar.gz |
IGNIETFERRO-1816 Update Python 3 from 3.9.12 to 3.10.4
ref:9f96be6d02ee8044fdd6f124b799b270c20ce641
Diffstat (limited to 'contrib/tools/python3/src/Objects')
62 files changed, 8452 insertions, 4346 deletions
diff --git a/contrib/tools/python3/src/Objects/abstract.c b/contrib/tools/python3/src/Objects/abstract.c index a5cbb12ff8..3ac85544de 100644 --- a/contrib/tools/python3/src/Objects/abstract.c +++ b/contrib/tools/python3/src/Objects/abstract.c @@ -3,8 +3,10 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_ceval.h" // _Py_EnterRecursiveCall() -#include "pycore_pyerrors.h" +#include "pycore_object.h" // _Py_CheckSlotResult() +#include "pycore_pyerrors.h" // _PyErr_Occurred() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_unionobject.h" // _PyUnion_Check() #include <ctype.h> #include <stddef.h> // offsetof() #include "longintrepr.h" @@ -23,9 +25,11 @@ type_error(const char *msg, PyObject *obj) static PyObject * null_error(void) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_SystemError, - "null argument to internal routine"); + PyThreadState *tstate = _PyThreadState_GET(); + if (!_PyErr_Occurred(tstate)) { + _PyErr_SetString(tstate, PyExc_SystemError, + "null argument to internal routine"); + } return NULL; } @@ -48,17 +52,15 @@ PyObject_Type(PyObject *o) Py_ssize_t PyObject_Size(PyObject *o) { - PySequenceMethods *m; - if (o == NULL) { null_error(); return -1; } - m = Py_TYPE(o)->tp_as_sequence; + PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; if (m && m->sq_length) { Py_ssize_t len = m->sq_length(o); - assert(len >= 0 || PyErr_Occurred()); + assert(_Py_CheckSlotResult(o, "__len__", len >= 0)); return len; } @@ -94,11 +96,12 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) if (_PyObject_HasLen(o)) { res = PyObject_Length(o); if (res < 0) { - assert(PyErr_Occurred()); - if (!PyErr_ExceptionMatches(PyExc_TypeError)) { + PyThreadState *tstate = _PyThreadState_GET(); + assert(_PyErr_Occurred(tstate)); + if (!_PyErr_ExceptionMatches(tstate, PyExc_TypeError)) { return -1; } - PyErr_Clear(); + _PyErr_Clear(tstate); } else { return res; @@ -114,8 +117,9 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) result = _PyObject_CallNoArg(hint); Py_DECREF(hint); if (result == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Clear(); + PyThreadState *tstate = _PyThreadState_GET(); + if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError)) { + _PyErr_Clear(tstate); return defaultvalue; } return -1; @@ -145,21 +149,18 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) PyObject * PyObject_GetItem(PyObject *o, PyObject *key) { - PyMappingMethods *m; - PySequenceMethods *ms; - if (o == NULL || key == NULL) { return null_error(); } - m = Py_TYPE(o)->tp_as_mapping; + PyMappingMethods *m = Py_TYPE(o)->tp_as_mapping; if (m && m->mp_subscript) { PyObject *item = m->mp_subscript(o, key); - assert((item != NULL) ^ (PyErr_Occurred() != NULL)); + assert(_Py_CheckSlotResult(o, "__getitem__", item != NULL)); return item; } - ms = Py_TYPE(o)->tp_as_sequence; + PySequenceMethods *ms = Py_TYPE(o)->tp_as_sequence; if (ms && ms->sq_item) { if (_PyIndex_Check(key)) { Py_ssize_t key_value; @@ -199,15 +200,17 @@ PyObject_GetItem(PyObject *o, PyObject *key) int PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value) { - PyMappingMethods *m; - if (o == NULL || key == NULL || value == NULL) { null_error(); return -1; } - m = Py_TYPE(o)->tp_as_mapping; - if (m && m->mp_ass_subscript) - return m->mp_ass_subscript(o, key, value); + + PyMappingMethods *m = Py_TYPE(o)->tp_as_mapping; + if (m && m->mp_ass_subscript) { + int res = m->mp_ass_subscript(o, key, value); + assert(_Py_CheckSlotResult(o, "__setitem__", res >= 0)); + return res; + } if (Py_TYPE(o)->tp_as_sequence) { if (_PyIndex_Check(key)) { @@ -231,15 +234,17 @@ PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value) int PyObject_DelItem(PyObject *o, PyObject *key) { - PyMappingMethods *m; - if (o == NULL || key == NULL) { null_error(); return -1; } - m = Py_TYPE(o)->tp_as_mapping; - if (m && m->mp_ass_subscript) - return m->mp_ass_subscript(o, key, (PyObject*)NULL); + + PyMappingMethods *m = Py_TYPE(o)->tp_as_mapping; + if (m && m->mp_ass_subscript) { + int res = m->mp_ass_subscript(o, key, (PyObject*)NULL); + assert(_Py_CheckSlotResult(o, "__delitem__", res >= 0)); + return res; + } if (Py_TYPE(o)->tp_as_sequence) { if (_PyIndex_Check(key)) { @@ -380,7 +385,9 @@ PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags) Py_TYPE(obj)->tp_name); return -1; } - return (*pb->bf_getbuffer)(obj, view, flags); + int res = (*pb->bf_getbuffer)(obj, view, flags); + assert(_Py_CheckSlotResult(obj, "getbuffer", res >= 0)); + return res; } static int @@ -708,7 +715,7 @@ PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len, { if (view == NULL) { PyErr_SetString(PyExc_BufferError, - "PyBuffer_FillInfo: view==NULL argument is obsolete"); + "PyBuffer_FillInfo: view==NULL argument is obsolete"); return -1; } @@ -749,8 +756,9 @@ PyBuffer_Release(Py_buffer *view) if (obj == NULL) return; pb = Py_TYPE(obj)->tp_as_buffer; - if (pb && pb->bf_releasebuffer) + if (pb && pb->bf_releasebuffer) { pb->bf_releasebuffer(obj, view); + } view->obj = NULL; Py_DECREF(obj); } @@ -790,10 +798,12 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) /* Find the (unbound!) __format__ method */ meth = _PyObject_LookupSpecial(obj, &PyId___format__); if (meth == NULL) { - if (!PyErr_Occurred()) - PyErr_Format(PyExc_TypeError, - "Type %.100s doesn't define __format__", - Py_TYPE(obj)->tp_name); + PyThreadState *tstate = _PyThreadState_GET(); + if (!_PyErr_Occurred(tstate)) { + _PyErr_Format(tstate, PyExc_TypeError, + "Type %.100s doesn't define __format__", + Py_TYPE(obj)->tp_name); + } goto done; } @@ -803,8 +813,8 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) if (result && !PyUnicode_Check(result)) { PyErr_Format(PyExc_TypeError, - "__format__ must return a str, not %.200s", - Py_TYPE(result)->tp_name); + "__format__ must return a str, not %.200s", + Py_TYPE(result)->tp_name); Py_DECREF(result); result = NULL; goto done; @@ -819,10 +829,10 @@ done: int PyNumber_Check(PyObject *o) { - return o && Py_TYPE(o)->tp_as_number && - (Py_TYPE(o)->tp_as_number->nb_index || - Py_TYPE(o)->tp_as_number->nb_int || - Py_TYPE(o)->tp_as_number->nb_float); + if (o == NULL) + return 0; + PyNumberMethods *nb = Py_TYPE(o)->tp_as_number; + return nb && (nb->nb_index || nb->nb_int || nb->nb_float || PyComplex_Check(o)); } /* Binary operators */ @@ -844,21 +854,33 @@ PyNumber_Check(PyObject *o) */ static PyObject * -binary_op1(PyObject *v, PyObject *w, const int op_slot) -{ - PyObject *x; - binaryfunc slotv = NULL; - binaryfunc slotw = NULL; - - if (Py_TYPE(v)->tp_as_number != NULL) +binary_op1(PyObject *v, PyObject *w, const int op_slot +#ifndef NDEBUG + , const char *op_name +#endif + ) +{ + binaryfunc slotv; + if (Py_TYPE(v)->tp_as_number != NULL) { slotv = NB_BINOP(Py_TYPE(v)->tp_as_number, op_slot); - if (!Py_IS_TYPE(w, Py_TYPE(v)) && - Py_TYPE(w)->tp_as_number != NULL) { + } + else { + slotv = NULL; + } + + binaryfunc slotw; + if (!Py_IS_TYPE(w, Py_TYPE(v)) && Py_TYPE(w)->tp_as_number != NULL) { slotw = NB_BINOP(Py_TYPE(w)->tp_as_number, op_slot); - if (slotw == slotv) + if (slotw == slotv) { slotw = NULL; + } + } + else { + slotw = NULL; } + if (slotv) { + PyObject *x; if (slotw && PyType_IsSubtype(Py_TYPE(w), Py_TYPE(v))) { x = slotw(v, w); if (x != Py_NotImplemented) @@ -867,19 +889,29 @@ binary_op1(PyObject *v, PyObject *w, const int op_slot) slotw = NULL; } x = slotv(v, w); - if (x != Py_NotImplemented) + assert(_Py_CheckSlotResult(v, op_name, x != NULL)); + if (x != Py_NotImplemented) { return x; + } Py_DECREF(x); /* can't do it */ } if (slotw) { - x = slotw(v, w); - if (x != Py_NotImplemented) + PyObject *x = slotw(v, w); + assert(_Py_CheckSlotResult(w, op_name, x != NULL)); + if (x != Py_NotImplemented) { return x; + } Py_DECREF(x); /* can't do it */ } Py_RETURN_NOTIMPLEMENTED; } +#ifdef NDEBUG +# define BINARY_OP1(v, w, op_slot, op_name) binary_op1(v, w, op_slot) +#else +# define BINARY_OP1(v, w, op_slot, op_name) binary_op1(v, w, op_slot, op_name) +#endif + static PyObject * binop_type_error(PyObject *v, PyObject *w, const char *op_name) { @@ -895,7 +927,7 @@ binop_type_error(PyObject *v, PyObject *w, const char *op_name) static PyObject * binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) { - PyObject *result = binary_op1(v, w, op_slot); + PyObject *result = BINARY_OP1(v, w, op_slot, op_name); if (result == Py_NotImplemented) { Py_DECREF(result); @@ -912,7 +944,6 @@ binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name) Py_TYPE(w)->tp_name); return NULL; } - return binop_type_error(v, w, op_name); } return result; @@ -931,70 +962,92 @@ ternary_op(PyObject *v, PyObject *w, PyObject *z, const int op_slot, - const char *op_name) + const char *op_name + ) { - PyNumberMethods *mv, *mw, *mz; - PyObject *x = NULL; - ternaryfunc slotv = NULL; - ternaryfunc slotw = NULL; - ternaryfunc slotz = NULL; + PyNumberMethods *mv = Py_TYPE(v)->tp_as_number; + PyNumberMethods *mw = Py_TYPE(w)->tp_as_number; - mv = Py_TYPE(v)->tp_as_number; - mw = Py_TYPE(w)->tp_as_number; - if (mv != NULL) + ternaryfunc slotv; + if (mv != NULL) { slotv = NB_TERNOP(mv, op_slot); + } + else { + slotv = NULL; + } + + ternaryfunc slotw; if (!Py_IS_TYPE(w, Py_TYPE(v)) && mw != NULL) { slotw = NB_TERNOP(mw, op_slot); - if (slotw == slotv) + if (slotw == slotv) { slotw = NULL; + } + } + else { + slotw = NULL; } + if (slotv) { + PyObject *x; if (slotw && PyType_IsSubtype(Py_TYPE(w), Py_TYPE(v))) { x = slotw(v, w, z); - if (x != Py_NotImplemented) + if (x != Py_NotImplemented) { return x; + } Py_DECREF(x); /* can't do it */ slotw = NULL; } x = slotv(v, w, z); - if (x != Py_NotImplemented) + assert(_Py_CheckSlotResult(v, op_name, x != NULL)); + if (x != Py_NotImplemented) { return x; + } Py_DECREF(x); /* can't do it */ } if (slotw) { - x = slotw(v, w, z); - if (x != Py_NotImplemented) + PyObject *x = slotw(v, w, z); + assert(_Py_CheckSlotResult(w, op_name, x != NULL)); + if (x != Py_NotImplemented) { return x; + } Py_DECREF(x); /* can't do it */ } - mz = Py_TYPE(z)->tp_as_number; + + PyNumberMethods *mz = Py_TYPE(z)->tp_as_number; if (mz != NULL) { - slotz = NB_TERNOP(mz, op_slot); - if (slotz == slotv || slotz == slotw) + ternaryfunc slotz = NB_TERNOP(mz, op_slot); + if (slotz == slotv || slotz == slotw) { slotz = NULL; + } if (slotz) { - x = slotz(v, w, z); - if (x != Py_NotImplemented) + PyObject *x = slotz(v, w, z); + assert(_Py_CheckSlotResult(z, op_name, x != NULL)); + if (x != Py_NotImplemented) { return x; + } Py_DECREF(x); /* can't do it */ } } - if (z == Py_None) + if (z == Py_None) { PyErr_Format( PyExc_TypeError, - "unsupported operand type(s) for ** or pow(): " + "unsupported operand type(s) for %.100s: " "'%.100s' and '%.100s'", + op_name, Py_TYPE(v)->tp_name, Py_TYPE(w)->tp_name); - else + } + else { PyErr_Format( PyExc_TypeError, - "unsupported operand type(s) for pow(): " + "unsupported operand type(s) for %.100s: " "'%.100s', '%.100s', '%.100s'", + op_name, Py_TYPE(v)->tp_name, Py_TYPE(w)->tp_name, Py_TYPE(z)->tp_name); + } return NULL; } @@ -1015,16 +1068,20 @@ BINARY_FUNC(PyNumber_Divmod, nb_divmod, "divmod()") PyObject * PyNumber_Add(PyObject *v, PyObject *w) { - PyObject *result = binary_op1(v, w, NB_SLOT(nb_add)); - if (result == Py_NotImplemented) { - PySequenceMethods *m = Py_TYPE(v)->tp_as_sequence; - Py_DECREF(result); - if (m && m->sq_concat) { - return (*m->sq_concat)(v, w); - } - result = binop_type_error(v, w, "+"); + PyObject *result = BINARY_OP1(v, w, NB_SLOT(nb_add), "+"); + if (result != Py_NotImplemented) { + return result; } - return result; + Py_DECREF(result); + + PySequenceMethods *m = Py_TYPE(v)->tp_as_sequence; + if (m && m->sq_concat) { + result = (*m->sq_concat)(v, w); + assert(_Py_CheckSlotResult(v, "+", result != NULL)); + return result; + } + + return binop_type_error(v, w, "+"); } static PyObject * @@ -1033,20 +1090,23 @@ sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) Py_ssize_t count; if (_PyIndex_Check(n)) { count = PyNumber_AsSsize_t(n, PyExc_OverflowError); - if (count == -1 && PyErr_Occurred()) + if (count == -1 && PyErr_Occurred()) { return NULL; + } } else { return type_error("can't multiply sequence by " "non-int of type '%.200s'", n); } - return (*repeatfunc)(seq, count); + PyObject *res = (*repeatfunc)(seq, count); + assert(_Py_CheckSlotResult(seq, "*", res != NULL)); + return res; } PyObject * PyNumber_Multiply(PyObject *v, PyObject *w) { - PyObject *result = binary_op1(v, w, NB_SLOT(nb_multiply)); + PyObject *result = BINARY_OP1(v, w, NB_SLOT(nb_multiply), "*"); if (result == Py_NotImplemented) { PySequenceMethods *mv = Py_TYPE(v)->tp_as_sequence; PySequenceMethods *mw = Py_TYPE(w)->tp_as_sequence; @@ -1109,27 +1169,42 @@ PyNumber_Power(PyObject *v, PyObject *w, PyObject *z) */ static PyObject * -binary_iop1(PyObject *v, PyObject *w, const int iop_slot, const int op_slot) +binary_iop1(PyObject *v, PyObject *w, const int iop_slot, const int op_slot +#ifndef NDEBUG + , const char *op_name +#endif + ) { PyNumberMethods *mv = Py_TYPE(v)->tp_as_number; if (mv != NULL) { binaryfunc slot = NB_BINOP(mv, iop_slot); if (slot) { PyObject *x = (slot)(v, w); + assert(_Py_CheckSlotResult(v, op_name, x != NULL)); if (x != Py_NotImplemented) { return x; } Py_DECREF(x); } } +#ifdef NDEBUG return binary_op1(v, w, op_slot); +#else + return binary_op1(v, w, op_slot, op_name); +#endif } +#ifdef NDEBUG +# define BINARY_IOP1(v, w, iop_slot, op_slot, op_name) binary_iop1(v, w, iop_slot, op_slot) +#else +# define BINARY_IOP1(v, w, iop_slot, op_slot, op_name) binary_iop1(v, w, iop_slot, op_slot, op_name) +#endif + static PyObject * binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot, const char *op_name) { - PyObject *result = binary_iop1(v, w, iop_slot, op_slot); + PyObject *result = BINARY_IOP1(v, w, iop_slot, op_slot, op_name); if (result == Py_NotImplemented) { Py_DECREF(result); return binop_type_error(v, w, op_name); @@ -1137,6 +1212,24 @@ binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot, return result; } +static PyObject * +ternary_iop(PyObject *v, PyObject *w, PyObject *z, const int iop_slot, const int op_slot, + const char *op_name) +{ + PyNumberMethods *mv = Py_TYPE(v)->tp_as_number; + if (mv != NULL) { + ternaryfunc slot = NB_TERNOP(mv, iop_slot); + if (slot) { + PyObject *x = (slot)(v, w, z); + if (x != Py_NotImplemented) { + return x; + } + Py_DECREF(x); + } + } + return ternary_op(v, w, z, op_slot, op_name); +} + #define INPLACE_BINOP(func, iop, op, op_name) \ PyObject * \ func(PyObject *v, PyObject *w) { \ @@ -1168,18 +1261,20 @@ PyNumber_InPlaceTrueDivide(PyObject *v, PyObject *w) PyObject * PyNumber_InPlaceAdd(PyObject *v, PyObject *w) { - PyObject *result = binary_iop1(v, w, NB_SLOT(nb_inplace_add), - NB_SLOT(nb_add)); + PyObject *result = BINARY_IOP1(v, w, NB_SLOT(nb_inplace_add), + NB_SLOT(nb_add), "+="); if (result == Py_NotImplemented) { PySequenceMethods *m = Py_TYPE(v)->tp_as_sequence; Py_DECREF(result); if (m != NULL) { - binaryfunc f = NULL; - f = m->sq_inplace_concat; - if (f == NULL) - f = m->sq_concat; - if (f != NULL) - return (*f)(v, w); + binaryfunc func = m->sq_inplace_concat; + if (func == NULL) + func = m->sq_concat; + if (func != NULL) { + result = func(v, w); + assert(_Py_CheckSlotResult(v, "+=", result != NULL)); + return result; + } } result = binop_type_error(v, w, "+="); } @@ -1189,8 +1284,8 @@ PyNumber_InPlaceAdd(PyObject *v, PyObject *w) PyObject * PyNumber_InPlaceMultiply(PyObject *v, PyObject *w) { - PyObject *result = binary_iop1(v, w, NB_SLOT(nb_inplace_multiply), - NB_SLOT(nb_multiply)); + PyObject *result = BINARY_IOP1(v, w, NB_SLOT(nb_inplace_multiply), + NB_SLOT(nb_multiply), "*="); if (result == Py_NotImplemented) { ssizeargfunc f = NULL; PySequenceMethods *mv = Py_TYPE(v)->tp_as_sequence; @@ -1232,13 +1327,8 @@ PyNumber_InPlaceRemainder(PyObject *v, PyObject *w) PyObject * PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z) { - if (Py_TYPE(v)->tp_as_number && - Py_TYPE(v)->tp_as_number->nb_inplace_power != NULL) { - return ternary_op(v, w, z, NB_SLOT(nb_inplace_power), "**="); - } - else { - return ternary_op(v, w, z, NB_SLOT(nb_power), "**="); - } + return ternary_iop(v, w, z, NB_SLOT(nb_inplace_power), + NB_SLOT(nb_power), "**="); } @@ -1247,15 +1337,16 @@ PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z) PyObject * PyNumber_Negative(PyObject *o) { - PyNumberMethods *m; - if (o == NULL) { return null_error(); } - m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_negative) - return (*m->nb_negative)(o); + PyNumberMethods *m = Py_TYPE(o)->tp_as_number; + if (m && m->nb_negative) { + PyObject *res = (*m->nb_negative)(o); + assert(_Py_CheckSlotResult(o, "__neg__", res != NULL)); + return res; + } return type_error("bad operand type for unary -: '%.200s'", o); } @@ -1263,15 +1354,16 @@ PyNumber_Negative(PyObject *o) PyObject * PyNumber_Positive(PyObject *o) { - PyNumberMethods *m; - if (o == NULL) { return null_error(); } - m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_positive) - return (*m->nb_positive)(o); + PyNumberMethods *m = Py_TYPE(o)->tp_as_number; + if (m && m->nb_positive) { + PyObject *res = (*m->nb_positive)(o); + assert(_Py_CheckSlotResult(o, "__pos__", res != NULL)); + return res; + } return type_error("bad operand type for unary +: '%.200s'", o); } @@ -1279,15 +1371,16 @@ PyNumber_Positive(PyObject *o) PyObject * PyNumber_Invert(PyObject *o) { - PyNumberMethods *m; - if (o == NULL) { return null_error(); } - m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_invert) - return (*m->nb_invert)(o); + PyNumberMethods *m = Py_TYPE(o)->tp_as_number; + if (m && m->nb_invert) { + PyObject *res = (*m->nb_invert)(o); + assert(_Py_CheckSlotResult(o, "__invert__", res != NULL)); + return res; + } return type_error("bad operand type for unary ~: '%.200s'", o); } @@ -1295,15 +1388,16 @@ PyNumber_Invert(PyObject *o) PyObject * PyNumber_Absolute(PyObject *o) { - PyNumberMethods *m; - if (o == NULL) { return null_error(); } - m = Py_TYPE(o)->tp_as_number; - if (m && m->nb_absolute) - return m->nb_absolute(o); + PyNumberMethods *m = Py_TYPE(o)->tp_as_number; + if (m && m->nb_absolute) { + PyObject *res = m->nb_absolute(o); + assert(_Py_CheckSlotResult(o, "__abs__", res != NULL)); + return res; + } return type_error("bad operand type for abs(): '%.200s'", o); } @@ -1317,13 +1411,13 @@ PyIndex_Check(PyObject *obj) /* Return a Python int from the object item. + Can return an instance of int subclass. Raise TypeError if the result is not an int or if the object cannot be interpreted as an index. */ PyObject * -PyNumber_Index(PyObject *item) +_PyNumber_Index(PyObject *item) { - PyObject *result = NULL; if (item == NULL) { return null_error(); } @@ -1338,9 +1432,13 @@ PyNumber_Index(PyObject *item) "as an integer", Py_TYPE(item)->tp_name); return NULL; } - result = Py_TYPE(item)->tp_as_number->nb_index(item); - if (!result || PyLong_CheckExact(result)) + + PyObject *result = Py_TYPE(item)->tp_as_number->nb_index(item); + assert(_Py_CheckSlotResult(item, "__index__", result != NULL)); + if (!result || PyLong_CheckExact(result)) { return result; + } + if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, "__index__ returned non-int (type %.200s)", @@ -1360,6 +1458,20 @@ PyNumber_Index(PyObject *item) return result; } +/* Return an exact Python int from the object item. + Raise TypeError if the result is not an int + or if the object cannot be interpreted as an index. +*/ +PyObject * +PyNumber_Index(PyObject *item) +{ + PyObject *result = _PyNumber_Index(item); + if (result != NULL && !PyLong_CheckExact(result)) { + Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); + } + return result; +} + /* Return an error on Overflow only if err is not NULL*/ Py_ssize_t @@ -1367,23 +1479,29 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) { Py_ssize_t result; PyObject *runerr; - PyObject *value = PyNumber_Index(item); + PyObject *value = _PyNumber_Index(item); if (value == NULL) return -1; /* We're done if PyLong_AsSsize_t() returns without error. */ result = PyLong_AsSsize_t(value); - if (result != -1 || !(runerr = PyErr_Occurred())) + if (result != -1) goto finish; + PyThreadState *tstate = _PyThreadState_GET(); + runerr = _PyErr_Occurred(tstate); + if (!runerr) { + goto finish; + } + /* Error handling code -- only manage OverflowError differently */ - if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) + if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) { goto finish; + } + _PyErr_Clear(tstate); - PyErr_Clear(); /* If no error-handling desired then the default clipping - is sufficient. - */ + is sufficient. */ if (!err) { assert(PyLong_Check(value)); /* Whether or not it is less than or equal to @@ -1396,9 +1514,9 @@ PyNumber_AsSsize_t(PyObject *item, PyObject *err) } else { /* Otherwise replace the error with caller's error object. */ - PyErr_Format(err, - "cannot fit '%.200s' into an index-sized integer", - Py_TYPE(item)->tp_name); + _PyErr_Format(tstate, err, + "cannot fit '%.200s' into an index-sized integer", + Py_TYPE(item)->tp_name); } finish: @@ -1426,18 +1544,35 @@ PyNumber_Long(PyObject *o) } m = Py_TYPE(o)->tp_as_number; if (m && m->nb_int) { /* This should include subclasses of int */ - result = _PyLong_FromNbInt(o); - if (result != NULL && !PyLong_CheckExact(result)) { - Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); + /* Convert using the nb_int slot, which should return something + of exact type int. */ + result = m->nb_int(o); + assert(_Py_CheckSlotResult(o, "__int__", result != NULL)); + if (!result || PyLong_CheckExact(result)) { + return result; } + + if (!PyLong_Check(result)) { + PyErr_Format(PyExc_TypeError, + "__int__ returned non-int (type %.200s)", + Py_TYPE(result)->tp_name); + Py_DECREF(result); + return NULL; + } + /* Issue #17576: warn if 'result' not of exact type int. */ + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "__int__ returned non-int (type %.200s). " + "The ability to return an instance of a strict subclass of int " + "is deprecated, and may be removed in a future version of Python.", + Py_TYPE(result)->tp_name)) { + Py_DECREF(result); + return NULL; + } + Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); return result; } if (m && m->nb_index) { - result = _PyLong_FromNbIndexOrNbInt(o); - if (result != NULL && !PyLong_CheckExact(result)) { - Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); - } - return result; + return PyNumber_Index(o); } trunc_func = _PyObject_LookupSpecial(o, &PyId___trunc__); if (trunc_func) { @@ -1452,8 +1587,7 @@ PyNumber_Long(PyObject *o) } /* __trunc__ is specified to return an Integral type, but int() needs to return an int. */ - m = Py_TYPE(result)->tp_as_number; - if (m == NULL || (m->nb_index == NULL && m->nb_int == NULL)) { + if (!PyIndex_Check(result)) { PyErr_Format( PyExc_TypeError, "__trunc__ returned non-Integral (type %.200s)", @@ -1461,17 +1595,14 @@ PyNumber_Long(PyObject *o) Py_DECREF(result); return NULL; } - Py_SETREF(result, _PyLong_FromNbIndexOrNbInt(result)); - if (result != NULL && !PyLong_CheckExact(result)) { - Py_SETREF(result, _PyLong_Copy((PyLongObject *)result)); - } + Py_SETREF(result, PyNumber_Index(result)); return result; } if (PyErr_Occurred()) return NULL; if (PyUnicode_Check(o)) - /* The below check is done in PyLong_FromUnicode(). */ + /* The below check is done in PyLong_FromUnicodeObject(). */ return PyLong_FromUnicodeObject(o, 10); if (PyBytes_Check(o)) @@ -1503,29 +1634,28 @@ PyNumber_Long(PyObject *o) } return type_error("int() argument must be a string, a bytes-like object " - "or a number, not '%.200s'", o); + "or a real number, not '%.200s'", o); } PyObject * PyNumber_Float(PyObject *o) { - PyNumberMethods *m; - if (o == NULL) { return null_error(); } if (PyFloat_CheckExact(o)) { - Py_INCREF(o); - return o; + return Py_NewRef(o); } - m = Py_TYPE(o)->tp_as_number; + + PyNumberMethods *m = Py_TYPE(o)->tp_as_number; if (m && m->nb_float) { /* This should include subclasses of float */ PyObject *res = m->nb_float(o); - double val; + assert(_Py_CheckSlotResult(o, "__float__", res != NULL)); if (!res || PyFloat_CheckExact(res)) { return res; } + if (!PyFloat_Check(res)) { PyErr_Format(PyExc_TypeError, "%.50s.__float__ returned non-float (type %.50s)", @@ -1542,12 +1672,13 @@ PyNumber_Float(PyObject *o) Py_DECREF(res); return NULL; } - val = PyFloat_AS_DOUBLE(res); + double val = PyFloat_AS_DOUBLE(res); Py_DECREF(res); return PyFloat_FromDouble(val); } + if (m && m->nb_index) { - PyObject *res = PyNumber_Index(o); + PyObject *res = _PyNumber_Index(o); if (!res) { return NULL; } @@ -1558,7 +1689,9 @@ PyNumber_Float(PyObject *o) } return PyFloat_FromDouble(val); } - if (PyFloat_Check(o)) { /* A float subclass with nb_float == NULL */ + + /* A float subclass with nb_float == NULL */ + if (PyFloat_Check(o)) { return PyFloat_FromDouble(PyFloat_AS_DOUBLE(o)); } return PyFloat_FromString(o); @@ -1573,7 +1706,7 @@ PyNumber_ToBase(PyObject *n, int base) "PyNumber_ToBase: base must be 2, 8, 10 or 16"); return NULL; } - PyObject *index = PyNumber_Index(n); + PyObject *index = _PyNumber_Index(n); if (!index) return NULL; PyObject *res = _PyLong_Format(index, base); @@ -1596,17 +1729,15 @@ PySequence_Check(PyObject *s) Py_ssize_t PySequence_Size(PyObject *s) { - PySequenceMethods *m; - if (s == NULL) { null_error(); return -1; } - m = Py_TYPE(s)->tp_as_sequence; + PySequenceMethods *m = Py_TYPE(s)->tp_as_sequence; if (m && m->sq_length) { Py_ssize_t len = m->sq_length(s); - assert(len >= 0 || PyErr_Occurred()); + assert(_Py_CheckSlotResult(s, "__len__", len >= 0)); return len; } @@ -1629,21 +1760,22 @@ PySequence_Length(PyObject *s) PyObject * PySequence_Concat(PyObject *s, PyObject *o) { - PySequenceMethods *m; - if (s == NULL || o == NULL) { return null_error(); } - m = Py_TYPE(s)->tp_as_sequence; - if (m && m->sq_concat) - return m->sq_concat(s, o); + PySequenceMethods *m = Py_TYPE(s)->tp_as_sequence; + if (m && m->sq_concat) { + PyObject *res = m->sq_concat(s, o); + assert(_Py_CheckSlotResult(s, "+", res != NULL)); + return res; + } /* Instances of user classes defining an __add__() method only have an nb_add slot, not an sq_concat slot. So we fall back to nb_add if both arguments appear to be sequences. */ if (PySequence_Check(s) && PySequence_Check(o)) { - PyObject *result = binary_op1(s, o, NB_SLOT(nb_add)); + PyObject *result = BINARY_OP1(s, o, NB_SLOT(nb_add), "+"); if (result != Py_NotImplemented) return result; Py_DECREF(result); @@ -1654,15 +1786,16 @@ PySequence_Concat(PyObject *s, PyObject *o) PyObject * PySequence_Repeat(PyObject *o, Py_ssize_t count) { - PySequenceMethods *m; - if (o == NULL) { return null_error(); } - m = Py_TYPE(o)->tp_as_sequence; - if (m && m->sq_repeat) - return m->sq_repeat(o, count); + PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; + if (m && m->sq_repeat) { + PyObject *res = m->sq_repeat(o, count); + assert(_Py_CheckSlotResult(o, "*", res != NULL)); + return res; + } /* Instances of user classes defining a __mul__() method only have an nb_multiply slot, not an sq_repeat slot. so we fall back @@ -1672,7 +1805,7 @@ PySequence_Repeat(PyObject *o, Py_ssize_t count) n = PyLong_FromSsize_t(count); if (n == NULL) return NULL; - result = binary_op1(o, n, NB_SLOT(nb_multiply)); + result = BINARY_OP1(o, n, NB_SLOT(nb_multiply), "*"); Py_DECREF(n); if (result != Py_NotImplemented) return result; @@ -1684,21 +1817,25 @@ PySequence_Repeat(PyObject *o, Py_ssize_t count) PyObject * PySequence_InPlaceConcat(PyObject *s, PyObject *o) { - PySequenceMethods *m; - if (s == NULL || o == NULL) { return null_error(); } - m = Py_TYPE(s)->tp_as_sequence; - if (m && m->sq_inplace_concat) - return m->sq_inplace_concat(s, o); - if (m && m->sq_concat) - return m->sq_concat(s, o); + PySequenceMethods *m = Py_TYPE(s)->tp_as_sequence; + if (m && m->sq_inplace_concat) { + PyObject *res = m->sq_inplace_concat(s, o); + assert(_Py_CheckSlotResult(s, "+=", res != NULL)); + return res; + } + if (m && m->sq_concat) { + PyObject *res = m->sq_concat(s, o); + assert(_Py_CheckSlotResult(s, "+", res != NULL)); + return res; + } if (PySequence_Check(s) && PySequence_Check(o)) { - PyObject *result = binary_iop1(s, o, NB_SLOT(nb_inplace_add), - NB_SLOT(nb_add)); + PyObject *result = BINARY_IOP1(s, o, NB_SLOT(nb_inplace_add), + NB_SLOT(nb_add), "+="); if (result != Py_NotImplemented) return result; Py_DECREF(result); @@ -1709,25 +1846,29 @@ PySequence_InPlaceConcat(PyObject *s, PyObject *o) PyObject * PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count) { - PySequenceMethods *m; - if (o == NULL) { return null_error(); } - m = Py_TYPE(o)->tp_as_sequence; - if (m && m->sq_inplace_repeat) - return m->sq_inplace_repeat(o, count); - if (m && m->sq_repeat) - return m->sq_repeat(o, count); + PySequenceMethods *m = Py_TYPE(o)->tp_as_sequence; + if (m && m->sq_inplace_repeat) { + PyObject *res = m->sq_inplace_repeat(o, count); + assert(_Py_CheckSlotResult(o, "*=", res != NULL)); + return res; + } + if (m && m->sq_repeat) { + PyObject *res = m->sq_repeat(o, count); + assert(_Py_CheckSlotResult(o, "*", res != NULL)); + return res; + } if (PySequence_Check(o)) { PyObject *n, *result; n = PyLong_FromSsize_t(count); if (n == NULL) return NULL; - result = binary_iop1(o, n, NB_SLOT(nb_inplace_multiply), - NB_SLOT(nb_multiply)); + result = BINARY_IOP1(o, n, NB_SLOT(nb_inplace_multiply), + NB_SLOT(nb_multiply), "*="); Py_DECREF(n); if (result != Py_NotImplemented) return result; @@ -1739,25 +1880,25 @@ PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count) PyObject * PySequence_GetItem(PyObject *s, Py_ssize_t i) { - PySequenceMethods *m; - if (s == NULL) { return null_error(); } - m = Py_TYPE(s)->tp_as_sequence; + PySequenceMethods *m = Py_TYPE(s)->tp_as_sequence; if (m && m->sq_item) { if (i < 0) { if (m->sq_length) { Py_ssize_t l = (*m->sq_length)(s); + assert(_Py_CheckSlotResult(s, "__len__", l >= 0)); if (l < 0) { - assert(PyErr_Occurred()); return NULL; } i += l; } } - return m->sq_item(s, i); + PyObject *res = m->sq_item(s, i); + assert(_Py_CheckSlotResult(s, "__getitem__", res != NULL)); + return res; } if (Py_TYPE(s)->tp_as_mapping && Py_TYPE(s)->tp_as_mapping->mp_subscript) { @@ -1769,19 +1910,18 @@ PySequence_GetItem(PyObject *s, Py_ssize_t i) PyObject * PySequence_GetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2) { - PyMappingMethods *mp; - if (!s) { return null_error(); } - mp = Py_TYPE(s)->tp_as_mapping; + PyMappingMethods *mp = Py_TYPE(s)->tp_as_mapping; if (mp && mp->mp_subscript) { - PyObject *res; PyObject *slice = _PySlice_FromIndices(i1, i2); - if (!slice) + if (!slice) { return NULL; - res = mp->mp_subscript(s, slice); + } + PyObject *res = mp->mp_subscript(s, slice); + assert(_Py_CheckSlotResult(s, "__getitem__", res != NULL)); Py_DECREF(slice); return res; } @@ -1792,26 +1932,26 @@ PySequence_GetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2) int PySequence_SetItem(PyObject *s, Py_ssize_t i, PyObject *o) { - PySequenceMethods *m; - if (s == NULL) { null_error(); return -1; } - m = Py_TYPE(s)->tp_as_sequence; + PySequenceMethods *m = Py_TYPE(s)->tp_as_sequence; if (m && m->sq_ass_item) { if (i < 0) { if (m->sq_length) { Py_ssize_t l = (*m->sq_length)(s); + assert(_Py_CheckSlotResult(s, "__len__", l >= 0)); if (l < 0) { - assert(PyErr_Occurred()); return -1; } i += l; } } - return m->sq_ass_item(s, i, o); + int res = m->sq_ass_item(s, i, o); + assert(_Py_CheckSlotResult(s, "__setitem__", res >= 0)); + return res; } if (Py_TYPE(s)->tp_as_mapping && Py_TYPE(s)->tp_as_mapping->mp_ass_subscript) { @@ -1825,26 +1965,26 @@ PySequence_SetItem(PyObject *s, Py_ssize_t i, PyObject *o) int PySequence_DelItem(PyObject *s, Py_ssize_t i) { - PySequenceMethods *m; - if (s == NULL) { null_error(); return -1; } - m = Py_TYPE(s)->tp_as_sequence; + PySequenceMethods *m = Py_TYPE(s)->tp_as_sequence; if (m && m->sq_ass_item) { if (i < 0) { if (m->sq_length) { Py_ssize_t l = (*m->sq_length)(s); + assert(_Py_CheckSlotResult(s, "__len__", l >= 0)); if (l < 0) { - assert(PyErr_Occurred()); return -1; } i += l; } } - return m->sq_ass_item(s, i, (PyObject *)NULL); + int res = m->sq_ass_item(s, i, (PyObject *)NULL); + assert(_Py_CheckSlotResult(s, "__delitem__", res >= 0)); + return res; } if (Py_TYPE(s)->tp_as_mapping && Py_TYPE(s)->tp_as_mapping->mp_ass_subscript) { @@ -1858,20 +1998,18 @@ PySequence_DelItem(PyObject *s, Py_ssize_t i) int PySequence_SetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2, PyObject *o) { - PyMappingMethods *mp; - if (s == NULL) { null_error(); return -1; } - mp = Py_TYPE(s)->tp_as_mapping; + PyMappingMethods *mp = Py_TYPE(s)->tp_as_mapping; if (mp && mp->mp_ass_subscript) { - int res; PyObject *slice = _PySlice_FromIndices(i1, i2); if (!slice) return -1; - res = mp->mp_ass_subscript(s, slice, o); + int res = mp->mp_ass_subscript(s, slice, o); + assert(_Py_CheckSlotResult(s, "__setitem__", res >= 0)); Py_DECREF(slice); return res; } @@ -1883,20 +2021,19 @@ PySequence_SetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2, PyObject *o) int PySequence_DelSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2) { - PyMappingMethods *mp; - if (s == NULL) { null_error(); return -1; } - mp = Py_TYPE(s)->tp_as_mapping; + PyMappingMethods *mp = Py_TYPE(s)->tp_as_mapping; if (mp && mp->mp_ass_subscript) { - int res; PyObject *slice = _PySlice_FromIndices(i1, i2); - if (!slice) + if (!slice) { return -1; - res = mp->mp_ass_subscript(s, slice, NULL); + } + int res = mp->mp_ass_subscript(s, slice, NULL); + assert(_Py_CheckSlotResult(s, "__delitem__", res >= 0)); Py_DECREF(slice); return res; } @@ -2027,8 +2164,10 @@ PySequence_Fast(PyObject *v, const char *m) it = PyObject_GetIter(v); if (it == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - PyErr_SetString(PyExc_TypeError, m); + PyThreadState *tstate = _PyThreadState_GET(); + if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError)) { + _PyErr_SetString(tstate, PyExc_TypeError, m); + } return NULL; } @@ -2141,11 +2280,13 @@ PySequence_Count(PyObject *s, PyObject *o) int PySequence_Contains(PyObject *seq, PyObject *ob) { - Py_ssize_t result; PySequenceMethods *sqm = Py_TYPE(seq)->tp_as_sequence; - if (sqm != NULL && sqm->sq_contains != NULL) - return (*sqm->sq_contains)(seq, ob); - result = _PySequence_IterSearch(seq, ob, PY_ITERSEARCH_CONTAINS); + if (sqm != NULL && sqm->sq_contains != NULL) { + int res = (*sqm->sq_contains)(seq, ob); + assert(_Py_CheckSlotResult(seq, "__contains__", res >= 0)); + return res; + } + Py_ssize_t result = _PySequence_IterSearch(seq, ob, PY_ITERSEARCH_CONTAINS); return Py_SAFE_DOWNCAST(result, Py_ssize_t, int); } @@ -2175,17 +2316,15 @@ PyMapping_Check(PyObject *o) Py_ssize_t PyMapping_Size(PyObject *o) { - PyMappingMethods *m; - if (o == NULL) { null_error(); return -1; } - m = Py_TYPE(o)->tp_as_mapping; + PyMappingMethods *m = Py_TYPE(o)->tp_as_mapping; if (m && m->mp_length) { Py_ssize_t len = m->mp_length(o); - assert(len >= 0 || PyErr_Occurred()); + assert(_Py_CheckSlotResult(o, "__len__", len >= 0)); return len; } @@ -2285,12 +2424,13 @@ method_output_as_list(PyObject *o, _Py_Identifier *meth_id) } it = PyObject_GetIter(meth_output); if (it == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) { - PyErr_Format(PyExc_TypeError, - "%.200s.%U() returned a non-iterable (type %.200s)", - Py_TYPE(o)->tp_name, - _PyUnicode_FromId(meth_id), - Py_TYPE(meth_output)->tp_name); + PyThreadState *tstate = _PyThreadState_GET(); + if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError)) { + _PyErr_Format(tstate, PyExc_TypeError, + "%.200s.%U() returned a non-iterable (type %.200s)", + Py_TYPE(o)->tp_name, + _PyUnicode_FromId(meth_id), + Py_TYPE(meth_output)->tp_name); } Py_DECREF(meth_output); return NULL; @@ -2441,8 +2581,10 @@ check_class(PyObject *cls, const char *error) PyObject *bases = abstract_get_bases(cls); if (bases == NULL) { /* Do not mask errors. */ - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_TypeError, error); + PyThreadState *tstate = _PyThreadState_GET(); + if (!_PyErr_Occurred(tstate)) { + _PyErr_SetString(tstate, PyExc_TypeError, error); + } return 0; } Py_DECREF(bases); @@ -2455,7 +2597,6 @@ object_isinstance(PyObject *inst, PyObject *cls) PyObject *icls; int retval; _Py_IDENTIFIER(__class__); - if (PyType_Check(cls)) { retval = PyObject_TypeCheck(inst, (PyTypeObject *)cls); if (retval == 0) { @@ -2475,7 +2616,7 @@ object_isinstance(PyObject *inst, PyObject *cls) } else { if (!check_class(cls, - "isinstance() arg 2 must be a type or tuple of types")) + "isinstance() arg 2 must be a type, a tuple of types, or a union")) return -1; retval = _PyObject_LookupAttrId(inst, &PyId___class__, &icls); if (icls != NULL) { @@ -2568,10 +2709,12 @@ recursive_issubclass(PyObject *derived, PyObject *cls) if (!check_class(derived, "issubclass() arg 1 must be a class")) return -1; - if (!check_class(cls, - "issubclass() arg 2 must be a class" - " or tuple of classes")) + + if (!_PyUnion_Check(cls) && !check_class(cls, + "issubclass() arg 2 must be a class," + " a tuple of classes, or a union")) { return -1; + } return abstract_issubclass(derived, cls); } @@ -2680,12 +2823,41 @@ PyObject_GetIter(PyObject *o) } } -#undef PyIter_Check +PyObject * +PyObject_GetAIter(PyObject *o) { + PyTypeObject *t = Py_TYPE(o); + unaryfunc f; + + if (t->tp_as_async == NULL || t->tp_as_async->am_aiter == NULL) { + return type_error("'%.200s' object is not an async iterable", o); + } + f = t->tp_as_async->am_aiter; + PyObject *it = (*f)(o); + if (it != NULL && !PyAIter_Check(it)) { + PyErr_Format(PyExc_TypeError, + "aiter() returned not an async iterator of type '%.100s'", + Py_TYPE(it)->tp_name); + Py_DECREF(it); + it = NULL; + } + return it; +} + +int +PyIter_Check(PyObject *obj) +{ + PyTypeObject *tp = Py_TYPE(obj); + return (tp->tp_iternext != NULL && + tp->tp_iternext != &_PyObject_NextNotImplemented); +} -int PyIter_Check(PyObject *obj) +int +PyAIter_Check(PyObject *obj) { - return Py_TYPE(obj)->tp_iternext != NULL && - Py_TYPE(obj)->tp_iternext != &_PyObject_NextNotImplemented; + PyTypeObject *tp = Py_TYPE(obj); + return (tp->tp_as_async != NULL && + tp->tp_as_async->am_anext != NULL && + tp->tp_as_async->am_anext != &_PyObject_NextNotImplemented); } /* Return next item. @@ -2700,13 +2872,42 @@ PyIter_Next(PyObject *iter) { PyObject *result; result = (*Py_TYPE(iter)->tp_iternext)(iter); - if (result == NULL && - PyErr_Occurred() && - PyErr_ExceptionMatches(PyExc_StopIteration)) - PyErr_Clear(); + if (result == NULL) { + PyThreadState *tstate = _PyThreadState_GET(); + if (_PyErr_Occurred(tstate) + && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) + { + _PyErr_Clear(tstate); + } + } return result; } +PySendResult +PyIter_Send(PyObject *iter, PyObject *arg, PyObject **result) +{ + _Py_IDENTIFIER(send); + assert(arg != NULL); + assert(result != NULL); + if (Py_TYPE(iter)->tp_as_async && Py_TYPE(iter)->tp_as_async->am_send) { + PySendResult res = Py_TYPE(iter)->tp_as_async->am_send(iter, arg, result); + assert(_Py_CheckSlotResult(iter, "am_send", res != PYGEN_ERROR)); + return res; + } + if (arg == Py_None && PyIter_Check(iter)) { + *result = Py_TYPE(iter)->tp_iternext(iter); + } + else { + *result = _PyObject_CallMethodIdOneArg(iter, &PyId_send, arg); + } + if (*result != NULL) { + return PYGEN_NEXT; + } + if (_PyGen_FetchStopIterationValue(result) == 0) { + return PYGEN_RETURN; + } + return PYGEN_ERROR; +} /* * Flatten a sequence of bytes() objects into a C array of diff --git a/contrib/tools/python3/src/Objects/boolobject.c b/contrib/tools/python3/src/Objects/boolobject.c index 720835b98a..b786966533 100644 --- a/contrib/tools/python3/src/Objects/boolobject.c +++ b/contrib/tools/python3/src/Objects/boolobject.c @@ -55,6 +55,30 @@ bool_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return PyBool_FromLong(ok); } +static PyObject * +bool_vectorcall(PyObject *type, PyObject * const*args, + size_t nargsf, PyObject *kwnames) +{ + long ok = 0; + if (!_PyArg_NoKwnames("bool", kwnames)) { + return NULL; + } + + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + if (!_PyArg_CheckPositional("bool", nargs, 0, 1)) { + return NULL; + } + + assert(PyType_Check(type)); + if (nargs) { + ok = PyObject_IsTrue(args[0]); + if (ok < 0) { + return NULL; + } + } + return PyBool_FromLong(ok); +} + /* Arithmetic operations redefined to return bool if both args are bool. */ static PyObject * @@ -170,6 +194,7 @@ PyTypeObject PyBool_Type = { 0, /* tp_init */ 0, /* tp_alloc */ bool_new, /* tp_new */ + .tp_vectorcall = bool_vectorcall, }; /* The objects representing bool values False and True */ diff --git a/contrib/tools/python3/src/Objects/bytearrayobject.c b/contrib/tools/python3/src/Objects/bytearrayobject.c index a1aa88086e..1ab9621b1f 100644 --- a/contrib/tools/python3/src/Objects/bytearrayobject.c +++ b/contrib/tools/python3/src/Objects/bytearrayobject.c @@ -13,31 +13,23 @@ class bytearray "PyByteArrayObject *" "&PyByteArray_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=5535b77c37a119e0]*/ +/* For PyByteArray_AS_STRING(). */ char _PyByteArray_empty_string[] = ""; -/* end nullbytes support */ - /* Helpers */ static int _getbytevalue(PyObject* arg, int *value) { - long face_value; + int overflow; + long face_value = PyLong_AsLongAndOverflow(arg, &overflow); - if (PyLong_Check(arg)) { - face_value = PyLong_AsLong(arg); - } else { - PyObject *index = PyNumber_Index(arg); - if (index == NULL) { - *value = -1; - return 0; - } - face_value = PyLong_AsLong(index); - Py_DECREF(index); + if (face_value == -1 && PyErr_Occurred()) { + *value = -1; + return 0; } - if (face_value < 0 || face_value >= 256) { - /* this includes the OverflowError in case the long is too large */ + /* this includes an overflow in converting to C long */ PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)"); *value = -1; return 0; @@ -273,7 +265,7 @@ PyByteArray_Concat(PyObject *a, PyObject *b) result = (PyByteArrayObject *) \ PyByteArray_FromStringAndSize(NULL, va.len + vb.len); - // result->ob_bytes is NULL if result is an empty string: + // result->ob_bytes is NULL if result is an empty bytearray: // if va.len + vb.len equals zero. if (result != NULL && result->ob_bytes != NULL) { memcpy(result->ob_bytes, va.buf, va.len); @@ -747,13 +739,20 @@ bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *valu } } +/*[clinic input] +bytearray.__init__ + + source as arg: object = NULL + encoding: str = NULL + errors: str = NULL + +[clinic start generated code]*/ + static int -bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds) +bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, + const char *encoding, const char *errors) +/*[clinic end generated code: output=4ce1304649c2f8b3 input=1141a7122eefd7b9]*/ { - static char *kwlist[] = {"source", "encoding", "errors", 0}; - PyObject *arg = NULL; - const char *encoding = NULL; - const char *errors = NULL; Py_ssize_t count; PyObject *it; PyObject *(*iternext)(PyObject *); @@ -764,11 +763,6 @@ bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds) return -1; } - /* Parse arguments */ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:bytearray", kwlist, - &arg, &encoding, &errors)) - return -1; - /* Make a quick exit if no first argument */ if (arg == NULL) { if (encoding != NULL || errors != NULL) { @@ -1012,26 +1006,20 @@ bytearray_richcompare(PyObject *self, PyObject *other, int op) { Py_ssize_t self_size, other_size; Py_buffer self_bytes, other_bytes; - int cmp, rc; - - /* Bytes can be compared to anything that supports the (binary) - buffer API. Except that a comparison with Unicode is always an - error, even if the comparison is for equality. */ - rc = PyObject_IsInstance(self, (PyObject*)&PyUnicode_Type); - if (!rc) - rc = PyObject_IsInstance(other, (PyObject*)&PyUnicode_Type); - if (rc < 0) - return NULL; - if (rc) { - if (_Py_GetConfig()->bytes_warning && (op == Py_EQ || op == Py_NE)) { - if (PyErr_WarnEx(PyExc_BytesWarning, - "Comparison between bytearray and string", 1)) - return NULL; + int cmp; + + if (!PyObject_CheckBuffer(self) || !PyObject_CheckBuffer(other)) { + if (PyUnicode_Check(self) || PyUnicode_Check(other)) { + if (_Py_GetConfig()->bytes_warning && (op == Py_EQ || op == Py_NE)) { + if (PyErr_WarnEx(PyExc_BytesWarning, + "Comparison between bytearray and string", 1)) + return NULL; + } } - Py_RETURN_NOTIMPLEMENTED; } + /* Bytearrays can be compared to anything that supports the buffer API. */ if (PyObject_GetBuffer(self, &self_bytes, PyBUF_SIMPLE) != 0) { PyErr_Clear(); Py_RETURN_NOTIMPLEMENTED; @@ -1339,7 +1327,7 @@ bytearray_translate_impl(PyByteArrayObject *self, PyObject *table, if (trans_table[c] != -1) *output++ = (char)trans_table[c]; } - /* Fix the size of the resulting string */ + /* Fix the size of the resulting bytearray */ if (inlen > 0) if (PyByteArray_Resize(result, output - output_start) < 0) { Py_CLEAR(result); @@ -1748,6 +1736,11 @@ bytearray_extend(PyByteArrayObject *self, PyObject *iterable_of_ints) } Py_DECREF(it); + if (PyErr_Occurred()) { + Py_DECREF(bytearray_obj); + return NULL; + } + /* Resize down to exact size. */ if (PyByteArray_Resize((PyObject *)bytearray_obj, len) < 0) { Py_DECREF(bytearray_obj); @@ -1760,10 +1753,7 @@ bytearray_extend(PyByteArrayObject *self, PyObject *iterable_of_ints) } Py_DECREF(bytearray_obj); - if (PyErr_Occurred()) { - return NULL; - } - + assert(!PyErr_Occurred()); Py_RETURN_NONE; } @@ -2094,7 +2084,7 @@ bytearray.hex How many bytes between separators. Positive values count from the right, negative values count from the left. -Create a str of hexadecimal numbers from a bytearray object. +Create a string of hexadecimal numbers from a bytearray object. Example: >>> value = bytearray([0xb9, 0x01, 0xef]) @@ -2110,7 +2100,7 @@ Example: static PyObject * bytearray_hex_impl(PyByteArrayObject *self, PyObject *sep, int bytes_per_sep) -/*[clinic end generated code: output=29c4e5ef72c565a0 input=814c15830ac8c4b5]*/ +/*[clinic end generated code: output=29c4e5ef72c565a0 input=808667e49bcccb54]*/ { char* argbuf = PyByteArray_AS_STRING(self); Py_ssize_t arglen = PyByteArray_GET_SIZE(self); @@ -2347,7 +2337,8 @@ PyTypeObject PyByteArray_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ &bytearray_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ bytearray_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -2363,13 +2354,13 @@ PyTypeObject PyByteArray_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - (initproc)bytearray_init, /* tp_init */ + (initproc)bytearray___init__, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ PyType_GenericNew, /* tp_new */ PyObject_Del, /* tp_free */ }; -/*********************** Bytes Iterator ****************************/ +/*********************** Bytearray Iterator ****************************/ typedef struct { PyObject_HEAD diff --git a/contrib/tools/python3/src/Objects/bytes_methods.c b/contrib/tools/python3/src/Objects/bytes_methods.c index 72daa1fdd5..994fb8a73c 100644 --- a/contrib/tools/python3/src/Objects/bytes_methods.c +++ b/contrib/tools/python3/src/Objects/bytes_methods.c @@ -100,14 +100,14 @@ Return True if B is empty or all characters in B are ASCII,\n\ False otherwise."); // Optimization is copied from ascii_decode in unicodeobject.c -/* Mask to quickly check whether a C 'long' contains a +/* Mask to quickly check whether a C 'size_t' contains a non-ASCII, UTF8-encoded char. */ -#if (SIZEOF_LONG == 8) -# define ASCII_CHAR_MASK 0x8080808080808080UL -#elif (SIZEOF_LONG == 4) -# define ASCII_CHAR_MASK 0x80808080UL +#if (SIZEOF_SIZE_T == 8) +# define ASCII_CHAR_MASK 0x8080808080808080ULL +#elif (SIZEOF_SIZE_T == 4) +# define ASCII_CHAR_MASK 0x80808080U #else -# error C 'long' size should be either 4 or 8! +# error C 'size_t' size should be either 4 or 8! #endif PyObject* @@ -115,20 +115,19 @@ _Py_bytes_isascii(const char *cptr, Py_ssize_t len) { const char *p = cptr; const char *end = p + len; - const char *aligned_end = (const char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG); while (p < end) { /* Fast path, see in STRINGLIB(utf8_decode) in stringlib/codecs.h for an explanation. */ - if (_Py_IS_ALIGNED(p, SIZEOF_LONG)) { + if (_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) { /* Help allocation */ const char *_p = p; - while (_p < aligned_end) { - unsigned long value = *(const unsigned long *) _p; + while (_p + SIZEOF_SIZE_T <= end) { + size_t value = *(const size_t *) _p; if (value & ASCII_CHAR_MASK) { Py_RETURN_FALSE; } - _p += SIZEOF_LONG; + _p += SIZEOF_SIZE_T; } p = _p; if (_p == end) diff --git a/contrib/tools/python3/src/Objects/bytesobject.c b/contrib/tools/python3/src/Objects/bytesobject.c index 25d9814dd6..eaedb0b568 100644 --- a/contrib/tools/python3/src/Objects/bytesobject.c +++ b/contrib/tools/python3/src/Objects/bytesobject.c @@ -4,8 +4,10 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_bytes_methods.h" -#include "pycore_object.h" +#include "pycore_bytes_methods.h" // _Py_bytes_startswith() +#include "pycore_format.h" // F_LJUST +#include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_object.h" // _PyObject_GC_TRACK #include "pycore_pymem.h" // PYMEM_CLEANBYTE #include "pystrhex.h" @@ -18,16 +20,13 @@ class bytes "PyBytesObject *" "&PyBytes_Type" #include "clinic/bytesobject.c.h" -static PyBytesObject *characters[UCHAR_MAX + 1]; -static PyBytesObject *nullstring; - _Py_IDENTIFIER(__bytes__); -/* PyBytesObject_SIZE gives the basic size of a string; any memory allocation - for a string of length n should request PyBytesObject_SIZE + n bytes. +/* PyBytesObject_SIZE gives the basic size of a bytes object; any memory allocation + for a bytes object of length n should request PyBytesObject_SIZE + n bytes. Using PyBytesObject_SIZE instead of sizeof(PyBytesObject) saves - 3 bytes per string allocation on a typical system. + 3 or 7 bytes per bytes object allocation on a typical system. */ #define PyBytesObject_SIZE (offsetof(PyBytesObject, ob_sval) + 1) @@ -35,6 +34,53 @@ _Py_IDENTIFIER(__bytes__); Py_LOCAL_INLINE(Py_ssize_t) _PyBytesWriter_GetSize(_PyBytesWriter *writer, char *str); + +static struct _Py_bytes_state* +get_bytes_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->bytes; +} + + +// Return a borrowed reference to the empty bytes string singleton. +static inline PyObject* bytes_get_empty(void) +{ + struct _Py_bytes_state *state = get_bytes_state(); + // bytes_get_empty() must not be called before _PyBytes_Init() + // or after _PyBytes_Fini() + assert(state->empty_string != NULL); + return state->empty_string; +} + + +// Return a strong reference to the empty bytes string singleton. +static inline PyObject* bytes_new_empty(void) +{ + PyObject *empty = bytes_get_empty(); + Py_INCREF(empty); + return (PyObject *)empty; +} + + +static int +bytes_create_empty_string_singleton(struct _Py_bytes_state *state) +{ + // Create the empty bytes string singleton + PyBytesObject *op = (PyBytesObject *)PyObject_Malloc(PyBytesObject_SIZE); + if (op == NULL) { + return -1; + } + _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, 0); + op->ob_shash = -1; + op->ob_sval[0] = '\0'; + + assert(state->empty_string == NULL); + state->empty_string = (PyObject *)op; + return 0; +} + + /* For PyBytes_FromString(), the parameter `str' points to a null-terminated string containing exactly `size' bytes. @@ -63,9 +109,8 @@ _PyBytes_FromSize(Py_ssize_t size, int use_calloc) PyBytesObject *op; assert(size >= 0); - if (size == 0 && (op = nullstring) != NULL) { - Py_INCREF(op); - return (PyObject *)op; + if (size == 0) { + return bytes_new_empty(); } if ((size_t)size > (size_t)PY_SSIZE_T_MAX - PyBytesObject_SIZE) { @@ -79,16 +124,13 @@ _PyBytes_FromSize(Py_ssize_t size, int use_calloc) op = (PyBytesObject *)PyObject_Calloc(1, PyBytesObject_SIZE + size); else op = (PyBytesObject *)PyObject_Malloc(PyBytesObject_SIZE + size); - if (op == NULL) + if (op == NULL) { return PyErr_NoMemory(); - (void)PyObject_INIT_VAR(op, &PyBytes_Type, size); + } + _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, size); op->ob_shash = -1; - if (!use_calloc) + if (!use_calloc) { op->ob_sval[size] = '\0'; - /* empty byte string singleton */ - if (size == 0) { - nullstring = op; - Py_INCREF(op); } return (PyObject *) op; } @@ -102,11 +144,16 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size) "Negative size passed to PyBytes_FromStringAndSize"); return NULL; } - if (size == 1 && str != NULL && - (op = characters[*str & UCHAR_MAX]) != NULL) - { - Py_INCREF(op); - return (PyObject *)op; + if (size == 1 && str != NULL) { + struct _Py_bytes_state *state = get_bytes_state(); + op = state->characters[*str & UCHAR_MAX]; + if (op != NULL) { + Py_INCREF(op); + return (PyObject *)op; + } + } + if (size == 0) { + return bytes_new_empty(); } op = (PyBytesObject *)_PyBytes_FromSize(size, 0); @@ -118,8 +165,9 @@ PyBytes_FromStringAndSize(const char *str, Py_ssize_t size) memcpy(op->ob_sval, str, size); /* share short strings */ if (size == 1) { - characters[*str & UCHAR_MAX] = op; + struct _Py_bytes_state *state = get_bytes_state(); Py_INCREF(op); + state->characters[*str & UCHAR_MAX] = op; } return (PyObject *) op; } @@ -137,29 +185,32 @@ PyBytes_FromString(const char *str) "byte string is too long"); return NULL; } - if (size == 0 && (op = nullstring) != NULL) { - Py_INCREF(op); - return (PyObject *)op; + + struct _Py_bytes_state *state = get_bytes_state(); + if (size == 0) { + return bytes_new_empty(); } - if (size == 1 && (op = characters[*str & UCHAR_MAX]) != NULL) { - Py_INCREF(op); - return (PyObject *)op; + else if (size == 1) { + op = state->characters[*str & UCHAR_MAX]; + if (op != NULL) { + Py_INCREF(op); + return (PyObject *)op; + } } /* Inline PyObject_NewVar */ - op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + size); - if (op == NULL) + op = (PyBytesObject *)PyObject_Malloc(PyBytesObject_SIZE + size); + if (op == NULL) { return PyErr_NoMemory(); - (void)PyObject_INIT_VAR(op, &PyBytes_Type, size); + } + _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, size); op->ob_shash = -1; memcpy(op->ob_sval, str, size+1); /* share short strings */ - if (size == 0) { - nullstring = op; - Py_INCREF(op); - } else if (size == 1) { - characters[*str & UCHAR_MAX] = op; + if (size == 1) { + assert(state->characters[*str & UCHAR_MAX] == NULL); Py_INCREF(op); + state->characters[*str & UCHAR_MAX] = op; } return (PyObject *) op; } @@ -256,27 +307,29 @@ PyBytes_FromFormatV(const char *format, va_list vargs) } case 'd': - if (longflag) + if (longflag) { sprintf(buffer, "%ld", va_arg(vargs, long)); - else if (size_tflag) - sprintf(buffer, "%" PY_FORMAT_SIZE_T "d", - va_arg(vargs, Py_ssize_t)); - else + } + else if (size_tflag) { + sprintf(buffer, "%zd", va_arg(vargs, Py_ssize_t)); + } + else { sprintf(buffer, "%d", va_arg(vargs, int)); + } assert(strlen(buffer) < sizeof(buffer)); WRITE_BYTES(buffer); break; case 'u': - if (longflag) - sprintf(buffer, "%lu", - va_arg(vargs, unsigned long)); - else if (size_tflag) - sprintf(buffer, "%" PY_FORMAT_SIZE_T "u", - va_arg(vargs, size_t)); - else - sprintf(buffer, "%u", - va_arg(vargs, unsigned int)); + if (longflag) { + sprintf(buffer, "%lu", va_arg(vargs, unsigned long)); + } + else if (size_tflag) { + sprintf(buffer, "%zu", va_arg(vargs, size_t)); + } + else { + sprintf(buffer, "%u", va_arg(vargs, unsigned int)); + } assert(strlen(buffer) < sizeof(buffer)); WRITE_BYTES(buffer); break; @@ -387,19 +440,6 @@ getnextarg(PyObject *args, Py_ssize_t arglen, Py_ssize_t *p_argidx) return NULL; } -/* Format codes - * F_LJUST '-' - * F_SIGN '+' - * F_BLANK ' ' - * F_ALT '#' - * F_ZERO '0' - */ -#define F_LJUST (1<<0) -#define F_SIGN (1<<1) -#define F_BLANK (1<<2) -#define F_ALT (1<<3) -#define F_ZERO (1<<4) - /* Returns a new reference to a PyBytes object, or NULL on failure. */ static char* @@ -455,25 +495,22 @@ formatlong(PyObject *v, int flags, int prec, int type) if (PyNumber_Check(v)) { /* make sure number is a type of integer for o, x, and X */ if (type == 'o' || type == 'x' || type == 'X') - iobj = PyNumber_Index(v); + iobj = _PyNumber_Index(v); else iobj = PyNumber_Long(v); - if (iobj == NULL) { - if (!PyErr_ExceptionMatches(PyExc_TypeError)) - return NULL; - } - else if (!PyLong_Check(iobj)) - Py_CLEAR(iobj); if (iobj != NULL) { + assert(PyLong_Check(iobj)); result = _PyUnicode_FormatLong(iobj, flags & F_ALT, prec, type); Py_DECREF(iobj); return result; } + if (!PyErr_ExceptionMatches(PyExc_TypeError)) + return NULL; } PyErr_Format(PyExc_TypeError, "%%%c format: %s is required, not %.200s", type, (type == 'o' || type == 'x' || type == 'X') ? "an integer" - : "a number", + : "a real number", Py_TYPE(v)->tp_name); return NULL; } @@ -490,26 +527,16 @@ byte_converter(PyObject *arg, char *p) return 1; } else { - PyObject *iobj; - long ival; int overflow; - /* make sure number is a type of integer */ - if (PyLong_Check(arg)) { - ival = PyLong_AsLongAndOverflow(arg, &overflow); - } - else { - iobj = PyNumber_Index(arg); - if (iobj == NULL) { - if (!PyErr_ExceptionMatches(PyExc_TypeError)) - return 0; + long ival = PyLong_AsLongAndOverflow(arg, &overflow); + if (ival == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { goto onError; } - ival = PyLong_AsLongAndOverflow(iobj, &overflow); - Py_DECREF(iobj); + return 0; } - if (!overflow && ival == -1 && PyErr_Occurred()) - goto onError; - if (overflow || !(0 <= ival && ival <= 255)) { + if (!(0 <= ival && ival <= 255)) { + /* this includes an overflow in converting to C long */ PyErr_SetString(PyExc_OverflowError, "%c arg not in range(256)"); return 0; @@ -1245,6 +1272,8 @@ PyBytes_AsStringAndSize(PyObject *obj, /* -------------------------------------------------------------------- */ /* Methods */ +#define STRINGLIB_GET_EMPTY() bytes_get_empty() + #include "stringlib/stringdefs.h" #include "stringlib/fastsearch.h" @@ -1257,6 +1286,8 @@ PyBytes_AsStringAndSize(PyObject *obj, #include "stringlib/transmogrify.h" +#undef STRINGLIB_GET_EMPTY + PyObject * PyBytes_Repr(PyObject *obj, int smartquotes) { @@ -1432,10 +1463,11 @@ bytes_repeat(PyBytesObject *a, Py_ssize_t n) "repeated bytes are too long"); return NULL; } - op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + nbytes); - if (op == NULL) + op = (PyBytesObject *)PyObject_Malloc(PyBytesObject_SIZE + nbytes); + if (op == NULL) { return PyErr_NoMemory(); - (void)PyObject_INIT_VAR(op, &PyBytes_Type, size); + } + _PyObject_InitVar((PyVarObject*)op, &PyBytes_Type, size); op->ob_shash = -1; op->ob_sval[size] = '\0'; if (Py_SIZE(a) == 1 && n > 0) { @@ -1494,36 +1526,19 @@ bytes_richcompare(PyBytesObject *a, PyBytesObject *b, int op) int c; Py_ssize_t len_a, len_b; Py_ssize_t min_len; - int rc; /* Make sure both arguments are strings. */ if (!(PyBytes_Check(a) && PyBytes_Check(b))) { if (_Py_GetConfig()->bytes_warning && (op == Py_EQ || op == Py_NE)) { - rc = PyObject_IsInstance((PyObject*)a, - (PyObject*)&PyUnicode_Type); - if (!rc) - rc = PyObject_IsInstance((PyObject*)b, - (PyObject*)&PyUnicode_Type); - if (rc < 0) - return NULL; - if (rc) { + if (PyUnicode_Check(a) || PyUnicode_Check(b)) { if (PyErr_WarnEx(PyExc_BytesWarning, "Comparison between bytes and string", 1)) return NULL; } - else { - rc = PyObject_IsInstance((PyObject*)a, - (PyObject*)&PyLong_Type); - if (!rc) - rc = PyObject_IsInstance((PyObject*)b, - (PyObject*)&PyLong_Type); - if (rc < 0) + if (PyLong_Check(a) || PyLong_Check(b)) { + if (PyErr_WarnEx(PyExc_BytesWarning, + "Comparison between bytes and int", 1)) return NULL; - if (rc) { - if (PyErr_WarnEx(PyExc_BytesWarning, - "Comparison between bytes and int", 1)) - return NULL; - } } } Py_RETURN_NOTIMPLEMENTED; @@ -1533,7 +1548,7 @@ bytes_richcompare(PyBytesObject *a, PyBytesObject *b, int op) case Py_EQ: case Py_LE: case Py_GE: - /* a string is equal to itself */ + /* a byte string is equal to itself */ Py_RETURN_TRUE; case Py_NE: case Py_LT: @@ -2122,7 +2137,7 @@ bytes_translate_impl(PyBytesObject *self, PyObject *table, Py_INCREF(input_obj); return input_obj; } - /* Fix the size of the resulting string */ + /* Fix the size of the resulting byte string */ if (inlen > 0) _PyBytes_Resize(&result, output - output_start); return result; @@ -2426,7 +2441,7 @@ bytes.hex How many bytes between separators. Positive values count from the right, negative values count from the left. -Create a str of hexadecimal numbers from a bytes object. +Create a string of hexadecimal numbers from a bytes object. Example: >>> value = b'\xb9\x01\xef' @@ -2442,7 +2457,7 @@ Example: static PyObject * bytes_hex_impl(PyBytesObject *self, PyObject *sep, int bytes_per_sep) -/*[clinic end generated code: output=1f134da504064139 input=f1238d3455990218]*/ +/*[clinic end generated code: output=1f134da504064139 input=1a21282b1f1ae595]*/ { const char *argbuf = PyBytes_AS_STRING(self); Py_ssize_t arglen = PyBytes_GET_SIZE(self); @@ -2536,24 +2551,27 @@ static PyNumberMethods bytes_as_number = { }; static PyObject * -bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +bytes_subtype_new(PyTypeObject *, PyObject *); + +/*[clinic input] +@classmethod +bytes.__new__ as bytes_new + + source as x: object = NULL + encoding: str = NULL + errors: str = NULL + +[clinic start generated code]*/ static PyObject * -bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, + const char *errors) +/*[clinic end generated code: output=1e0c471be311a425 input=f0a966d19b7262b4]*/ { - PyObject *x = NULL; - const char *encoding = NULL; - const char *errors = NULL; - PyObject *new = NULL; + PyObject *bytes; PyObject *func; Py_ssize_t size; - static char *kwlist[] = {"source", "encoding", "errors", 0}; - if (type != &PyBytes_Type) - return bytes_subtype_new(type, args, kwds); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:bytes", kwlist, &x, - &encoding, &errors)) - return NULL; if (x == NULL) { if (encoding != NULL || errors != NULL) { PyErr_SetString(PyExc_TypeError, @@ -2562,78 +2580,73 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) "errors without a string argument"); return NULL; } - return PyBytes_FromStringAndSize(NULL, 0); + bytes = PyBytes_FromStringAndSize(NULL, 0); } - - if (encoding != NULL) { + else if (encoding != NULL) { /* Encode via the codec registry */ if (!PyUnicode_Check(x)) { PyErr_SetString(PyExc_TypeError, "encoding without a string argument"); return NULL; } - new = PyUnicode_AsEncodedString(x, encoding, errors); - if (new == NULL) - return NULL; - assert(PyBytes_Check(new)); - return new; + bytes = PyUnicode_AsEncodedString(x, encoding, errors); } - - if (errors != NULL) { + else if (errors != NULL) { PyErr_SetString(PyExc_TypeError, PyUnicode_Check(x) ? "string argument without an encoding" : "errors without a string argument"); return NULL; } - /* We'd like to call PyObject_Bytes here, but we need to check for an integer argument before deferring to PyBytes_FromObject, something PyObject_Bytes doesn't do. */ - func = _PyObject_LookupSpecial(x, &PyId___bytes__); - if (func != NULL) { - new = _PyObject_CallNoArg(func); + else if ((func = _PyObject_LookupSpecial(x, &PyId___bytes__)) != NULL) { + bytes = _PyObject_CallNoArg(func); Py_DECREF(func); - if (new == NULL) + if (bytes == NULL) return NULL; - if (!PyBytes_Check(new)) { + if (!PyBytes_Check(bytes)) { PyErr_Format(PyExc_TypeError, - "__bytes__ returned non-bytes (type %.200s)", - Py_TYPE(new)->tp_name); - Py_DECREF(new); + "__bytes__ returned non-bytes (type %.200s)", + Py_TYPE(bytes)->tp_name); + Py_DECREF(bytes); return NULL; } - return new; } else if (PyErr_Occurred()) return NULL; - - if (PyUnicode_Check(x)) { + else if (PyUnicode_Check(x)) { PyErr_SetString(PyExc_TypeError, "string argument without an encoding"); return NULL; } /* Is it an integer? */ - if (_PyIndex_Check(x)) { + else if (_PyIndex_Check(x)) { size = PyNumber_AsSsize_t(x, PyExc_OverflowError); if (size == -1 && PyErr_Occurred()) { if (!PyErr_ExceptionMatches(PyExc_TypeError)) return NULL; PyErr_Clear(); /* fall through */ + bytes = PyBytes_FromObject(x); } else { if (size < 0) { PyErr_SetString(PyExc_ValueError, "negative count"); return NULL; } - new = _PyBytes_FromSize(size, 1); - if (new == NULL) - return NULL; - return new; + bytes = _PyBytes_FromSize(size, 1); } } + else { + bytes = PyBytes_FromObject(x); + } + + if (bytes != NULL && type != &PyBytes_Type) { + Py_SETREF(bytes, bytes_subtype_new(type, bytes)); + } - return PyBytes_FromObject(x); + return bytes; } static PyObject* @@ -2746,7 +2759,7 @@ _PyBytes_FromIterator(PyObject *it, PyObject *x) Py_ssize_t i, size; _PyBytesWriter writer; - /* For iterator version, create a string object and resize as needed */ + /* For iterator version, create a bytes object and resize as needed */ size = PyObject_LengthHint(x, 64); if (size == -1 && PyErr_Occurred()) return NULL; @@ -2845,15 +2858,12 @@ PyBytes_FromObject(PyObject *x) } static PyObject * -bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +bytes_subtype_new(PyTypeObject *type, PyObject *tmp) { - PyObject *tmp, *pnew; + PyObject *pnew; Py_ssize_t n; assert(PyType_IsSubtype(type, &PyBytes_Type)); - tmp = bytes_new(&PyBytes_Type, args, kwds); - if (tmp == NULL) - return NULL; assert(PyBytes_Check(tmp)); n = PyBytes_GET_SIZE(tmp); pnew = type->tp_alloc(type, n); @@ -2863,7 +2873,6 @@ bytes_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ((PyBytesObject *)pnew)->ob_shash = ((PyBytesObject *)tmp)->ob_shash; } - Py_DECREF(tmp); return pnew; } @@ -2903,7 +2912,8 @@ PyTypeObject PyBytes_Type = { 0, /* tp_setattro */ &bytes_as_buffer, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_BYTES_SUBCLASS, /* tp_flags */ + Py_TPFLAGS_BYTES_SUBCLASS | + _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ bytes_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -3021,9 +3031,9 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) goto error; } if (newsize == 0) { - *pv = _PyBytes_FromSize(0, 0); + *pv = bytes_new_empty(); Py_DECREF(v); - return (*pv == NULL) ? -1 : 0; + return 0; } /* XXX UNREF/NEWREF interface should be more symmetrical */ #ifdef Py_REF_DEBUG @@ -3033,9 +3043,9 @@ _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) _Py_ForgetReference(v); #endif *pv = (PyObject *) - PyObject_REALLOC(v, PyBytesObject_SIZE + newsize); + PyObject_Realloc(v, PyBytesObject_SIZE + newsize); if (*pv == NULL) { - PyObject_Del(v); + PyObject_Free(v); PyErr_NoMemory(); return -1; } @@ -3052,13 +3062,26 @@ error: return -1; } + +PyStatus +_PyBytes_Init(PyInterpreterState *interp) +{ + struct _Py_bytes_state *state = &interp->bytes; + if (bytes_create_empty_string_singleton(state) < 0) { + return _PyStatus_NO_MEMORY(); + } + return _PyStatus_OK(); +} + + void -_PyBytes_Fini(void) +_PyBytes_Fini(PyInterpreterState *interp) { - int i; - for (i = 0; i < UCHAR_MAX + 1; i++) - Py_CLEAR(characters[i]); - Py_CLEAR(nullstring); + struct _Py_bytes_state* state = &interp->bytes; + for (int i = 0; i < UCHAR_MAX + 1; i++) { + Py_CLEAR(state->characters[i]); + } + Py_CLEAR(state->empty_string); } /*********************** Bytes Iterator ****************************/ @@ -3088,7 +3111,6 @@ static PyObject * striter_next(striterobject *it) { PyBytesObject *seq; - PyObject *item; assert(it != NULL); seq = it->it_seq; @@ -3097,11 +3119,8 @@ striter_next(striterobject *it) assert(PyBytes_Check(seq)); if (it->it_index < PyBytes_GET_SIZE(seq)) { - item = PyLong_FromLong( - (unsigned char)seq->ob_sval[it->it_index]); - if (item != NULL) - ++it->it_index; - return item; + return PyLong_FromLong( + (unsigned char)seq->ob_sval[it->it_index++]); } it->it_seq = NULL; diff --git a/contrib/tools/python3/src/Objects/call.c b/contrib/tools/python3/src/Objects/call.c index 87dc0dbbdb..960c37e196 100644 --- a/contrib/tools/python3/src/Objects/call.c +++ b/contrib/tools/python3/src/Objects/call.c @@ -1,11 +1,11 @@ #include "Python.h" -#include "pycore_call.h" -#include "pycore_ceval.h" // _PyEval_EvalFrame() -#include "pycore_object.h" -#include "pycore_pyerrors.h" -#include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_tupleobject.h" -#include "frameobject.h" +#include "pycore_call.h" // _PyObject_CallNoArgTstate() +#include "pycore_ceval.h" // _PyEval_EvalFrame() +#include "pycore_object.h" // _PyObject_GC_TRACK() +#include "pycore_pyerrors.h" // _PyErr_Occurred() +#include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_tuple.h" // _PyTuple_ITEMS() +#include "frameobject.h" // _PyFrame_New_NoTrack() static PyObject *const * @@ -39,16 +39,16 @@ _Py_CheckFunctionResult(PyThreadState *tstate, PyObject *callable, if (!_PyErr_Occurred(tstate)) { if (callable) _PyErr_Format(tstate, PyExc_SystemError, - "%R returned NULL without setting an error", + "%R returned NULL without setting an exception", callable); else _PyErr_Format(tstate, PyExc_SystemError, - "%s returned NULL without setting an error", + "%s returned NULL without setting an exception", where); #ifdef Py_DEBUG /* Ensure that the bug is caught in debug mode. Py_FatalError() logs the SystemError exception raised above. */ - Py_FatalError("a function returned NULL without setting an error"); + Py_FatalError("a function returned NULL without setting an exception"); #endif return NULL; } @@ -60,17 +60,17 @@ _Py_CheckFunctionResult(PyThreadState *tstate, PyObject *callable, if (callable) { _PyErr_FormatFromCauseTstate( tstate, PyExc_SystemError, - "%R returned a result with an error set", callable); + "%R returned a result with an exception set", callable); } else { _PyErr_FormatFromCauseTstate( tstate, PyExc_SystemError, - "%s returned a result with an error set", where); + "%s returned a result with an exception set", where); } #ifdef Py_DEBUG /* Ensure that the bug is caught in debug mode. Py_FatalError() logs the SystemError exception raised above. */ - Py_FatalError("a function returned a result with an error set"); + Py_FatalError("a function returned a result with an exception set"); #endif return NULL; } @@ -79,6 +79,30 @@ _Py_CheckFunctionResult(PyThreadState *tstate, PyObject *callable, } +int +_Py_CheckSlotResult(PyObject *obj, const char *slot_name, int success) +{ + PyThreadState *tstate = _PyThreadState_GET(); + if (!success) { + if (!_PyErr_Occurred(tstate)) { + _Py_FatalErrorFormat(__func__, + "Slot %s of type %s failed " + "without setting an exception", + slot_name, Py_TYPE(obj)->tp_name); + } + } + else { + if (_PyErr_Occurred(tstate)) { + _Py_FatalErrorFormat(__func__, + "Slot %s of type %s succeeded " + "with an exception set", + slot_name, Py_TYPE(obj)->tp_name); + } + } + return 1; +} + + /* --- Core PyObject call functions ------------------------------- */ /* Call a callable Python object without any arguments */ @@ -304,106 +328,24 @@ PyCFunction_Call(PyObject *callable, PyObject *args, PyObject *kwargs) /* --- PyFunction call functions ---------------------------------- */ -static PyObject* _Py_HOT_FUNCTION -function_code_fastcall(PyThreadState *tstate, PyCodeObject *co, - PyObject *const *args, Py_ssize_t nargs, - PyObject *globals) -{ - assert(tstate != NULL); - assert(globals != NULL); - - /* XXX Perhaps we should create a specialized - _PyFrame_New_NoTrack() that doesn't take locals, but does - take builtins without sanity checking them. - */ - PyFrameObject *f = _PyFrame_New_NoTrack(tstate, co, globals, NULL); - if (f == NULL) { - return NULL; - } - - PyObject **fastlocals = f->f_localsplus; - - for (Py_ssize_t i = 0; i < nargs; i++) { - Py_INCREF(*args); - fastlocals[i] = *args++; - } - PyObject *result = _PyEval_EvalFrame(tstate, f, 0); - - if (Py_REFCNT(f) > 1) { - Py_DECREF(f); - _PyObject_GC_TRACK(f); - } - else { - ++tstate->recursion_depth; - Py_DECREF(f); - --tstate->recursion_depth; - } - return result; -} - - PyObject * _PyFunction_Vectorcall(PyObject *func, PyObject* const* stack, size_t nargsf, PyObject *kwnames) { assert(PyFunction_Check(func)); - assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - + PyFrameConstructor *f = PyFunction_AS_FRAME_CONSTRUCTOR(func); Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); assert(nargs >= 0); - Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); - /* kwnames must only contain strings and all keys must be unique */ - PyThreadState *tstate = _PyThreadState_GET(); - PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func); - PyObject *globals = PyFunction_GET_GLOBALS(func); - PyObject *argdefs = PyFunction_GET_DEFAULTS(func); - - if (co->co_kwonlyargcount == 0 && nkwargs == 0 && - (co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) - { - if (argdefs == NULL && co->co_argcount == nargs) { - return function_code_fastcall(tstate, co, stack, nargs, globals); - } - else if (nargs == 0 && argdefs != NULL - && co->co_argcount == PyTuple_GET_SIZE(argdefs)) { - /* function called with no arguments, but all parameters have - a default value: use default values as arguments .*/ - stack = _PyTuple_ITEMS(argdefs); - return function_code_fastcall(tstate, co, - stack, PyTuple_GET_SIZE(argdefs), - globals); - } - } - - PyObject *kwdefs = PyFunction_GET_KW_DEFAULTS(func); - PyObject *closure = PyFunction_GET_CLOSURE(func); - PyObject *name = ((PyFunctionObject *)func) -> func_name; - PyObject *qualname = ((PyFunctionObject *)func) -> func_qualname; - - PyObject **d; - Py_ssize_t nd; - if (argdefs != NULL) { - d = _PyTuple_ITEMS(argdefs); - nd = PyTuple_GET_SIZE(argdefs); - assert(nd <= INT_MAX); + assert(nargs == 0 || stack != NULL); + if (((PyCodeObject *)f->fc_code)->co_flags & CO_OPTIMIZED) { + return _PyEval_Vector(tstate, f, NULL, stack, nargs, kwnames); } else { - d = NULL; - nd = 0; - } - return _PyEval_EvalCode(tstate, - (PyObject*)co, globals, (PyObject *)NULL, - stack, nargs, - nkwargs ? _PyTuple_ITEMS(kwnames) : NULL, - stack + nargs, - nkwargs, 1, - d, (int)nd, kwdefs, - closure, name, qualname); + return _PyEval_Vector(tstate, f, f->fc_globals, stack, nargs, kwnames); + } } - /* --- More complex call functions -------------------------------- */ /* External interface to call any callable object. diff --git a/contrib/tools/python3/src/Objects/capsule.c b/contrib/tools/python3/src/Objects/capsule.c index ed24cc1d6a..800a6c4b25 100644 --- a/contrib/tools/python3/src/Objects/capsule.c +++ b/contrib/tools/python3/src/Objects/capsule.c @@ -198,7 +198,7 @@ PyCapsule_Import(const char *name, int no_block) void *return_value = NULL; char *trace; size_t name_length = (strlen(name) + 1) * sizeof(char); - char *name_dup = (char *)PyMem_MALLOC(name_length); + char *name_dup = (char *)PyMem_Malloc(name_length); if (!name_dup) { return PyErr_NoMemory(); @@ -247,7 +247,7 @@ PyCapsule_Import(const char *name, int no_block) EXIT: Py_XDECREF(object); if (name_dup) { - PyMem_FREE(name_dup); + PyMem_Free(name_dup); } return return_value; } @@ -260,7 +260,7 @@ capsule_dealloc(PyObject *o) if (capsule->destructor) { capsule->destructor(o); } - PyObject_DEL(o); + PyObject_Free(o); } diff --git a/contrib/tools/python3/src/Objects/clinic/bytearrayobject.c.h b/contrib/tools/python3/src/Objects/clinic/bytearrayobject.c.h index 35ba1ff3d5..1e3f197561 100644 --- a/contrib/tools/python3/src/Objects/clinic/bytearrayobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/bytearrayobject.c.h @@ -2,6 +2,75 @@ preserve [clinic start generated code]*/ +static int +bytearray___init___impl(PyByteArrayObject *self, PyObject *arg, + const char *encoding, const char *errors); + +static int +bytearray___init__(PyObject *self, PyObject *args, PyObject *kwargs) +{ + int return_value = -1; + static const char * const _keywords[] = {"source", "encoding", "errors", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "bytearray", 0}; + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *arg = NULL; + const char *encoding = NULL; + const char *errors = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 3, 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + arg = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[1]) { + if (!PyUnicode_Check(fastargs[1])) { + _PyArg_BadArgument("bytearray", "argument 'encoding'", "str", fastargs[1]); + goto exit; + } + Py_ssize_t encoding_length; + encoding = PyUnicode_AsUTF8AndSize(fastargs[1], &encoding_length); + if (encoding == NULL) { + goto exit; + } + if (strlen(encoding) != (size_t)encoding_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (!PyUnicode_Check(fastargs[2])) { + _PyArg_BadArgument("bytearray", "argument 'errors'", "str", fastargs[2]); + goto exit; + } + Py_ssize_t errors_length; + errors = PyUnicode_AsUTF8AndSize(fastargs[2], &errors_length); + if (errors == NULL) { + goto exit; + } + if (strlen(errors) != (size_t)errors_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +skip_optional_pos: + return_value = bytearray___init___impl((PyByteArrayObject *)self, arg, encoding, errors); + +exit: + return return_value; +} + PyDoc_STRVAR(bytearray_clear__doc__, "clear($self, /)\n" "--\n" @@ -268,14 +337,9 @@ bytearray_replace(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nar if (nargs < 3) { goto skip_optional; } - if (PyFloat_Check(args[2])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[2]); + PyObject *iobj = _PyNumber_Index(args[2]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -346,14 +410,9 @@ bytearray_split(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs goto skip_optional_pos; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[1]); + PyObject *iobj = _PyNumber_Index(args[1]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -450,14 +509,9 @@ bytearray_rsplit(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t narg goto skip_optional_pos; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[1]); + PyObject *iobj = _PyNumber_Index(args[1]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -519,14 +573,9 @@ bytearray_insert(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t narg if (!_PyArg_CheckPositional("insert", nargs, 2, 2)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -617,14 +666,9 @@ bytearray_pop(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs) if (nargs < 1) { goto skip_optional; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -896,11 +940,6 @@ bytearray_splitlines(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t if (!noptargs) { goto skip_optional_pos; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } keepends = _PyLong_AsInt(args[0]); if (keepends == -1 && PyErr_Occurred()) { goto exit; @@ -951,7 +990,7 @@ PyDoc_STRVAR(bytearray_hex__doc__, "hex($self, /, sep=<unrepresentable>, bytes_per_sep=1)\n" "--\n" "\n" -"Create a str of hexadecimal numbers from a bytearray object.\n" +"Create a string of hexadecimal numbers from a bytearray object.\n" "\n" " sep\n" " An optional single character or byte to separate hex bytes.\n" @@ -1000,11 +1039,6 @@ bytearray_hex(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t nargs, goto skip_optional_pos; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } bytes_per_sep = _PyLong_AsInt(args[1]); if (bytes_per_sep == -1 && PyErr_Occurred()) { goto exit; @@ -1058,11 +1092,6 @@ bytearray_reduce_ex(PyByteArrayObject *self, PyObject *const *args, Py_ssize_t n if (nargs < 1) { goto skip_optional; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } proto = _PyLong_AsInt(args[0]); if (proto == -1 && PyErr_Occurred()) { goto exit; @@ -1091,4 +1120,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) { return bytearray_sizeof_impl(self); } -/*[clinic end generated code: output=b2919f76709e48dc input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a82659f581e55629 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/bytesobject.c.h b/contrib/tools/python3/src/Objects/clinic/bytesobject.c.h index 063a3777b4..9e365ce1a0 100644 --- a/contrib/tools/python3/src/Objects/clinic/bytesobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/bytesobject.c.h @@ -46,14 +46,9 @@ bytes_split(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje goto skip_optional_pos; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[1]); + PyObject *iobj = _PyNumber_Index(args[1]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -202,14 +197,9 @@ bytes_rsplit(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObj goto skip_optional_pos; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[1]); + PyObject *iobj = _PyNumber_Index(args[1]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -493,14 +483,9 @@ bytes_replace(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs) if (nargs < 3) { goto skip_optional; } - if (PyFloat_Check(args[2])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[2]); + PyObject *iobj = _PyNumber_Index(args[2]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -715,11 +700,6 @@ bytes_splitlines(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, P if (!noptargs) { goto skip_optional_pos; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } keepends = _PyLong_AsInt(args[0]); if (keepends == -1 && PyErr_Occurred()) { goto exit; @@ -770,7 +750,7 @@ PyDoc_STRVAR(bytes_hex__doc__, "hex($self, /, sep=<unrepresentable>, bytes_per_sep=1)\n" "--\n" "\n" -"Create a str of hexadecimal numbers from a bytes object.\n" +"Create a string of hexadecimal numbers from a bytes object.\n" "\n" " sep\n" " An optional single character or byte to separate hex bytes.\n" @@ -819,11 +799,6 @@ bytes_hex(PyBytesObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject goto skip_optional_pos; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } bytes_per_sep = _PyLong_AsInt(args[1]); if (bytes_per_sep == -1 && PyErr_Occurred()) { goto exit; @@ -834,4 +809,73 @@ skip_optional_pos: exit: return return_value; } -/*[clinic end generated code: output=220388917d7bf751 input=a9049054013a1b77]*/ + +static PyObject * +bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, + const char *errors); + +static PyObject * +bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"source", "encoding", "errors", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "bytes", 0}; + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *x = NULL; + const char *encoding = NULL; + const char *errors = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 3, 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + x = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[1]) { + if (!PyUnicode_Check(fastargs[1])) { + _PyArg_BadArgument("bytes", "argument 'encoding'", "str", fastargs[1]); + goto exit; + } + Py_ssize_t encoding_length; + encoding = PyUnicode_AsUTF8AndSize(fastargs[1], &encoding_length); + if (encoding == NULL) { + goto exit; + } + if (strlen(encoding) != (size_t)encoding_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (!PyUnicode_Check(fastargs[2])) { + _PyArg_BadArgument("bytes", "argument 'errors'", "str", fastargs[2]); + goto exit; + } + Py_ssize_t errors_length; + errors = PyUnicode_AsUTF8AndSize(fastargs[2], &errors_length); + if (errors == NULL) { + goto exit; + } + if (strlen(errors) != (size_t)errors_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +skip_optional_pos: + return_value = bytes_new_impl(type, x, encoding, errors); + +exit: + return return_value; +} +/*[clinic end generated code: output=b3f0ec2753246b9c input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/codeobject.c.h b/contrib/tools/python3/src/Objects/clinic/codeobject.c.h index 1dd82278cf..bae2ab0764 100644 --- a/contrib/tools/python3/src/Objects/clinic/codeobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/codeobject.c.h @@ -2,13 +2,149 @@ preserve [clinic start generated code]*/ +PyDoc_STRVAR(code_new__doc__, +"code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n" +" flags, codestring, constants, names, varnames, filename, name,\n" +" firstlineno, linetable, freevars=(), cellvars=(), /)\n" +"--\n" +"\n" +"Create a code object. Not for the faint of heart."); + +static PyObject * +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, + int firstlineno, PyObject *linetable, PyObject *freevars, + PyObject *cellvars); + +static PyObject * +code_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + int argcount; + int posonlyargcount; + int kwonlyargcount; + int nlocals; + int stacksize; + int flags; + PyObject *code; + PyObject *consts; + PyObject *names; + PyObject *varnames; + PyObject *filename; + PyObject *name; + int firstlineno; + PyObject *linetable; + PyObject *freevars = NULL; + PyObject *cellvars = NULL; + + if ((type == &PyCode_Type) && + !_PyArg_NoKeywords("code", kwargs)) { + goto exit; + } + if (!_PyArg_CheckPositional("code", PyTuple_GET_SIZE(args), 14, 16)) { + goto exit; + } + argcount = _PyLong_AsInt(PyTuple_GET_ITEM(args, 0)); + if (argcount == -1 && PyErr_Occurred()) { + goto exit; + } + posonlyargcount = _PyLong_AsInt(PyTuple_GET_ITEM(args, 1)); + if (posonlyargcount == -1 && PyErr_Occurred()) { + goto exit; + } + kwonlyargcount = _PyLong_AsInt(PyTuple_GET_ITEM(args, 2)); + if (kwonlyargcount == -1 && PyErr_Occurred()) { + goto exit; + } + nlocals = _PyLong_AsInt(PyTuple_GET_ITEM(args, 3)); + if (nlocals == -1 && PyErr_Occurred()) { + goto exit; + } + stacksize = _PyLong_AsInt(PyTuple_GET_ITEM(args, 4)); + if (stacksize == -1 && PyErr_Occurred()) { + goto exit; + } + flags = _PyLong_AsInt(PyTuple_GET_ITEM(args, 5)); + if (flags == -1 && PyErr_Occurred()) { + goto exit; + } + if (!PyBytes_Check(PyTuple_GET_ITEM(args, 6))) { + _PyArg_BadArgument("code", "argument 7", "bytes", PyTuple_GET_ITEM(args, 6)); + goto exit; + } + code = PyTuple_GET_ITEM(args, 6); + if (!PyTuple_Check(PyTuple_GET_ITEM(args, 7))) { + _PyArg_BadArgument("code", "argument 8", "tuple", PyTuple_GET_ITEM(args, 7)); + goto exit; + } + consts = PyTuple_GET_ITEM(args, 7); + if (!PyTuple_Check(PyTuple_GET_ITEM(args, 8))) { + _PyArg_BadArgument("code", "argument 9", "tuple", PyTuple_GET_ITEM(args, 8)); + goto exit; + } + names = PyTuple_GET_ITEM(args, 8); + if (!PyTuple_Check(PyTuple_GET_ITEM(args, 9))) { + _PyArg_BadArgument("code", "argument 10", "tuple", PyTuple_GET_ITEM(args, 9)); + goto exit; + } + varnames = PyTuple_GET_ITEM(args, 9); + if (!PyUnicode_Check(PyTuple_GET_ITEM(args, 10))) { + _PyArg_BadArgument("code", "argument 11", "str", PyTuple_GET_ITEM(args, 10)); + goto exit; + } + if (PyUnicode_READY(PyTuple_GET_ITEM(args, 10)) == -1) { + goto exit; + } + filename = PyTuple_GET_ITEM(args, 10); + if (!PyUnicode_Check(PyTuple_GET_ITEM(args, 11))) { + _PyArg_BadArgument("code", "argument 12", "str", PyTuple_GET_ITEM(args, 11)); + goto exit; + } + if (PyUnicode_READY(PyTuple_GET_ITEM(args, 11)) == -1) { + goto exit; + } + name = PyTuple_GET_ITEM(args, 11); + firstlineno = _PyLong_AsInt(PyTuple_GET_ITEM(args, 12)); + if (firstlineno == -1 && PyErr_Occurred()) { + goto exit; + } + if (!PyBytes_Check(PyTuple_GET_ITEM(args, 13))) { + _PyArg_BadArgument("code", "argument 14", "bytes", PyTuple_GET_ITEM(args, 13)); + goto exit; + } + linetable = PyTuple_GET_ITEM(args, 13); + if (PyTuple_GET_SIZE(args) < 15) { + goto skip_optional; + } + if (!PyTuple_Check(PyTuple_GET_ITEM(args, 14))) { + _PyArg_BadArgument("code", "argument 15", "tuple", PyTuple_GET_ITEM(args, 14)); + goto exit; + } + freevars = PyTuple_GET_ITEM(args, 14); + if (PyTuple_GET_SIZE(args) < 16) { + goto skip_optional; + } + if (!PyTuple_Check(PyTuple_GET_ITEM(args, 15))) { + _PyArg_BadArgument("code", "argument 16", "tuple", PyTuple_GET_ITEM(args, 15)); + goto exit; + } + cellvars = PyTuple_GET_ITEM(args, 15); +skip_optional: + return_value = code_new_impl(type, argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize, flags, code, consts, names, varnames, filename, name, firstlineno, linetable, freevars, cellvars); + +exit: + return return_value; +} + PyDoc_STRVAR(code_replace__doc__, "replace($self, /, *, co_argcount=-1, co_posonlyargcount=-1,\n" " co_kwonlyargcount=-1, co_nlocals=-1, co_stacksize=-1,\n" " co_flags=-1, co_firstlineno=-1, co_code=None, co_consts=None,\n" " co_names=None, co_varnames=None, co_freevars=None,\n" " co_cellvars=None, co_filename=None, co_name=None,\n" -" co_lnotab=None)\n" +" co_linetable=None)\n" "--\n" "\n" "Return a copy of the code object with new values for the specified fields."); @@ -24,13 +160,13 @@ code_replace_impl(PyCodeObject *self, int co_argcount, PyObject *co_consts, PyObject *co_names, PyObject *co_varnames, PyObject *co_freevars, PyObject *co_cellvars, PyObject *co_filename, - PyObject *co_name, PyBytesObject *co_lnotab); + PyObject *co_name, PyBytesObject *co_linetable); static PyObject * code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; - static const char * const _keywords[] = {"co_argcount", "co_posonlyargcount", "co_kwonlyargcount", "co_nlocals", "co_stacksize", "co_flags", "co_firstlineno", "co_code", "co_consts", "co_names", "co_varnames", "co_freevars", "co_cellvars", "co_filename", "co_name", "co_lnotab", NULL}; + static const char * const _keywords[] = {"co_argcount", "co_posonlyargcount", "co_kwonlyargcount", "co_nlocals", "co_stacksize", "co_flags", "co_firstlineno", "co_code", "co_consts", "co_names", "co_varnames", "co_freevars", "co_cellvars", "co_filename", "co_name", "co_linetable", NULL}; static _PyArg_Parser _parser = {NULL, _keywords, "replace", 0}; PyObject *argsbuf[16]; Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; @@ -49,7 +185,7 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje PyObject *co_cellvars = self->co_cellvars; PyObject *co_filename = self->co_filename; PyObject *co_name = self->co_name; - PyBytesObject *co_lnotab = (PyBytesObject *)self->co_lnotab; + PyBytesObject *co_linetable = (PyBytesObject *)self->co_linetable; args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); if (!args) { @@ -59,11 +195,6 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje goto skip_optional_kwonly; } if (args[0]) { - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } co_argcount = _PyLong_AsInt(args[0]); if (co_argcount == -1 && PyErr_Occurred()) { goto exit; @@ -73,11 +204,6 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[1]) { - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } co_posonlyargcount = _PyLong_AsInt(args[1]); if (co_posonlyargcount == -1 && PyErr_Occurred()) { goto exit; @@ -87,11 +213,6 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[2]) { - if (PyFloat_Check(args[2])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } co_kwonlyargcount = _PyLong_AsInt(args[2]); if (co_kwonlyargcount == -1 && PyErr_Occurred()) { goto exit; @@ -101,11 +222,6 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[3]) { - if (PyFloat_Check(args[3])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } co_nlocals = _PyLong_AsInt(args[3]); if (co_nlocals == -1 && PyErr_Occurred()) { goto exit; @@ -115,11 +231,6 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[4]) { - if (PyFloat_Check(args[4])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } co_stacksize = _PyLong_AsInt(args[4]); if (co_stacksize == -1 && PyErr_Occurred()) { goto exit; @@ -129,11 +240,6 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[5]) { - if (PyFloat_Check(args[5])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } co_flags = _PyLong_AsInt(args[5]); if (co_flags == -1 && PyErr_Occurred()) { goto exit; @@ -143,11 +249,6 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (args[6]) { - if (PyFloat_Check(args[6])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } co_firstlineno = _PyLong_AsInt(args[6]); if (co_firstlineno == -1 && PyErr_Occurred()) { goto exit; @@ -243,14 +344,14 @@ code_replace(PyCodeObject *self, PyObject *const *args, Py_ssize_t nargs, PyObje } } if (!PyBytes_Check(args[15])) { - _PyArg_BadArgument("replace", "argument 'co_lnotab'", "bytes", args[15]); + _PyArg_BadArgument("replace", "argument 'co_linetable'", "bytes", args[15]); goto exit; } - co_lnotab = (PyBytesObject *)args[15]; + co_linetable = (PyBytesObject *)args[15]; skip_optional_kwonly: - return_value = code_replace_impl(self, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_lnotab); + return_value = code_replace_impl(self, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags, co_firstlineno, co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, co_linetable); exit: return return_value; } -/*[clinic end generated code: output=27fe34e82106b220 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e3091c7baaaaa420 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/complexobject.c.h b/contrib/tools/python3/src/Objects/clinic/complexobject.c.h index 8caa910d03..557fbf9752 100644 --- a/contrib/tools/python3/src/Objects/clinic/complexobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/complexobject.c.h @@ -2,6 +2,73 @@ preserve [clinic start generated code]*/ +PyDoc_STRVAR(complex_conjugate__doc__, +"conjugate($self, /)\n" +"--\n" +"\n" +"Return the complex conjugate of its argument. (3-4j).conjugate() == 3+4j."); + +#define COMPLEX_CONJUGATE_METHODDEF \ + {"conjugate", (PyCFunction)complex_conjugate, METH_NOARGS, complex_conjugate__doc__}, + +static PyObject * +complex_conjugate_impl(PyComplexObject *self); + +static PyObject * +complex_conjugate(PyComplexObject *self, PyObject *Py_UNUSED(ignored)) +{ + return complex_conjugate_impl(self); +} + +PyDoc_STRVAR(complex___getnewargs____doc__, +"__getnewargs__($self, /)\n" +"--\n" +"\n"); + +#define COMPLEX___GETNEWARGS___METHODDEF \ + {"__getnewargs__", (PyCFunction)complex___getnewargs__, METH_NOARGS, complex___getnewargs____doc__}, + +static PyObject * +complex___getnewargs___impl(PyComplexObject *self); + +static PyObject * +complex___getnewargs__(PyComplexObject *self, PyObject *Py_UNUSED(ignored)) +{ + return complex___getnewargs___impl(self); +} + +PyDoc_STRVAR(complex___format____doc__, +"__format__($self, format_spec, /)\n" +"--\n" +"\n" +"Convert to a string according to format_spec."); + +#define COMPLEX___FORMAT___METHODDEF \ + {"__format__", (PyCFunction)complex___format__, METH_O, complex___format____doc__}, + +static PyObject * +complex___format___impl(PyComplexObject *self, PyObject *format_spec); + +static PyObject * +complex___format__(PyComplexObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *format_spec; + + if (!PyUnicode_Check(arg)) { + _PyArg_BadArgument("__format__", "argument", "str", arg); + goto exit; + } + if (PyUnicode_READY(arg) == -1) { + goto exit; + } + format_spec = arg; + return_value = complex___format___impl(self, format_spec); + +exit: + return return_value; +} + PyDoc_STRVAR(complex_new__doc__, "complex(real=0, imag=0)\n" "--\n" @@ -23,7 +90,7 @@ complex_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) PyObject * const *fastargs; Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; - PyObject *r = _PyLong_Zero; + PyObject *r = NULL; PyObject *i = NULL; fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 2, 0, argsbuf); @@ -46,4 +113,4 @@ skip_optional_pos: exit: return return_value; } -/*[clinic end generated code: output=a0fe23fdbdc9b06b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=056cac3226d94967 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/dictobject.c.h b/contrib/tools/python3/src/Objects/clinic/dictobject.c.h index 7395e3bceb..beb3f360f8 100644 --- a/contrib/tools/python3/src/Objects/clinic/dictobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/dictobject.c.h @@ -122,7 +122,8 @@ PyDoc_STRVAR(dict_pop__doc__, "\n" "D.pop(k[,d]) -> v, remove specified key and return the corresponding value.\n" "\n" -"If key is not found, default is returned if given, otherwise KeyError is raised"); +"If the key is not found, return the default if given; otherwise,\n" +"raise a KeyError."); #define DICT_POP_METHODDEF \ {"pop", (PyCFunction)(void(*)(void))dict_pop, METH_FASTCALL, dict_pop__doc__}, @@ -190,4 +191,4 @@ dict___reversed__(PyDictObject *self, PyObject *Py_UNUSED(ignored)) { return dict___reversed___impl(self); } -/*[clinic end generated code: output=4d98145508da8fa3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7b77c16e43d6735a input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/floatobject.c.h b/contrib/tools/python3/src/Objects/clinic/floatobject.c.h index 6ecdd9e66e..494c0a2271 100644 --- a/contrib/tools/python3/src/Objects/clinic/floatobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/floatobject.c.h @@ -206,7 +206,7 @@ static PyObject * float_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyObject *return_value = NULL; - PyObject *x = _PyLong_Zero; + PyObject *x = NULL; if ((type == &PyFloat_Type) && !_PyArg_NoKeywords("float", kwargs)) { @@ -387,4 +387,4 @@ float___format__(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=a6af179ec5f83fba input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f4aae29054273cb5 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/listobject.c.h b/contrib/tools/python3/src/Objects/clinic/listobject.c.h index ed137c95a8..01e31d76cf 100644 --- a/contrib/tools/python3/src/Objects/clinic/listobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/listobject.c.h @@ -24,14 +24,9 @@ list_insert(PyListObject *self, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("insert", nargs, 2, 2)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -128,14 +123,9 @@ list_pop(PyListObject *self, PyObject *const *args, Py_ssize_t nargs) if (nargs < 1) { goto skip_optional; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -196,11 +186,6 @@ list_sort(PyListObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject goto skip_optional_kwonly; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } reverse = _PyLong_AsInt(args[1]); if (reverse == -1 && PyErr_Occurred()) { goto exit; @@ -367,4 +352,4 @@ list___reversed__(PyListObject *self, PyObject *Py_UNUSED(ignored)) { return list___reversed___impl(self); } -/*[clinic end generated code: output=1ff61490c091d165 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=0063aad535edf62d input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/longobject.c.h b/contrib/tools/python3/src/Objects/clinic/longobject.c.h index 27e8dfe935..4bd47b116f 100644 --- a/contrib/tools/python3/src/Objects/clinic/longobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/longobject.c.h @@ -87,6 +87,40 @@ exit: return return_value; } +PyDoc_STRVAR(int___round____doc__, +"__round__($self, ndigits=<unrepresentable>, /)\n" +"--\n" +"\n" +"Rounding an Integral returns itself.\n" +"\n" +"Rounding with an ndigits argument also returns an integer."); + +#define INT___ROUND___METHODDEF \ + {"__round__", (PyCFunction)(void(*)(void))int___round__, METH_FASTCALL, int___round____doc__}, + +static PyObject * +int___round___impl(PyObject *self, PyObject *o_ndigits); + +static PyObject * +int___round__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *o_ndigits = NULL; + + if (!_PyArg_CheckPositional("__round__", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + o_ndigits = args[0]; +skip_optional: + return_value = int___round___impl(self, o_ndigits); + +exit: + return return_value; +} + PyDoc_STRVAR(int___sizeof____doc__, "__sizeof__($self, /)\n" "--\n" @@ -138,6 +172,31 @@ int_bit_length(PyObject *self, PyObject *Py_UNUSED(ignored)) return int_bit_length_impl(self); } +PyDoc_STRVAR(int_bit_count__doc__, +"bit_count($self, /)\n" +"--\n" +"\n" +"Number of ones in the binary representation of the absolute value of self.\n" +"\n" +"Also known as the population count.\n" +"\n" +">>> bin(13)\n" +"\'0b1101\'\n" +">>> (13).bit_count()\n" +"3"); + +#define INT_BIT_COUNT_METHODDEF \ + {"bit_count", (PyCFunction)int_bit_count, METH_NOARGS, int_bit_count__doc__}, + +static PyObject * +int_bit_count_impl(PyObject *self); + +static PyObject * +int_bit_count(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return int_bit_count_impl(self); +} + PyDoc_STRVAR(int_as_integer_ratio__doc__, "as_integer_ratio($self, /)\n" "--\n" @@ -209,14 +268,9 @@ int_to_bytes(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject * if (!args) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -313,4 +367,4 @@ skip_optional_kwonly: exit: return return_value; } -/*[clinic end generated code: output=77bc3b2615822cb8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=ea18e51af5b53591 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/memoryobject.c.h b/contrib/tools/python3/src/Objects/clinic/memoryobject.c.h index 75ac201126..4a682f69d6 100644 --- a/contrib/tools/python3/src/Objects/clinic/memoryobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/memoryobject.c.h @@ -2,6 +2,198 @@ preserve [clinic start generated code]*/ +PyDoc_STRVAR(memoryview__doc__, +"memoryview(object)\n" +"--\n" +"\n" +"Create a new memoryview object which references the given object."); + +static PyObject * +memoryview_impl(PyTypeObject *type, PyObject *object); + +static PyObject * +memoryview(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"object", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "memoryview", 0}; + PyObject *argsbuf[1]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + PyObject *object; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 1, 1, 0, argsbuf); + if (!fastargs) { + goto exit; + } + object = fastargs[0]; + return_value = memoryview_impl(type, object); + +exit: + return return_value; +} + +PyDoc_STRVAR(memoryview_release__doc__, +"release($self, /)\n" +"--\n" +"\n" +"Release the underlying buffer exposed by the memoryview object."); + +#define MEMORYVIEW_RELEASE_METHODDEF \ + {"release", (PyCFunction)memoryview_release, METH_NOARGS, memoryview_release__doc__}, + +static PyObject * +memoryview_release_impl(PyMemoryViewObject *self); + +static PyObject * +memoryview_release(PyMemoryViewObject *self, PyObject *Py_UNUSED(ignored)) +{ + return memoryview_release_impl(self); +} + +PyDoc_STRVAR(memoryview_cast__doc__, +"cast($self, /, format, shape=<unrepresentable>)\n" +"--\n" +"\n" +"Cast a memoryview to a new format or shape."); + +#define MEMORYVIEW_CAST_METHODDEF \ + {"cast", (PyCFunction)(void(*)(void))memoryview_cast, METH_FASTCALL|METH_KEYWORDS, memoryview_cast__doc__}, + +static PyObject * +memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format, + PyObject *shape); + +static PyObject * +memoryview_cast(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"format", "shape", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "cast", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *format; + PyObject *shape = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { + goto exit; + } + if (!PyUnicode_Check(args[0])) { + _PyArg_BadArgument("cast", "argument 'format'", "str", args[0]); + goto exit; + } + if (PyUnicode_READY(args[0]) == -1) { + goto exit; + } + format = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + shape = args[1]; +skip_optional_pos: + return_value = memoryview_cast_impl(self, format, shape); + +exit: + return return_value; +} + +PyDoc_STRVAR(memoryview_toreadonly__doc__, +"toreadonly($self, /)\n" +"--\n" +"\n" +"Return a readonly version of the memoryview."); + +#define MEMORYVIEW_TOREADONLY_METHODDEF \ + {"toreadonly", (PyCFunction)memoryview_toreadonly, METH_NOARGS, memoryview_toreadonly__doc__}, + +static PyObject * +memoryview_toreadonly_impl(PyMemoryViewObject *self); + +static PyObject * +memoryview_toreadonly(PyMemoryViewObject *self, PyObject *Py_UNUSED(ignored)) +{ + return memoryview_toreadonly_impl(self); +} + +PyDoc_STRVAR(memoryview_tolist__doc__, +"tolist($self, /)\n" +"--\n" +"\n" +"Return the data in the buffer as a list of elements."); + +#define MEMORYVIEW_TOLIST_METHODDEF \ + {"tolist", (PyCFunction)memoryview_tolist, METH_NOARGS, memoryview_tolist__doc__}, + +static PyObject * +memoryview_tolist_impl(PyMemoryViewObject *self); + +static PyObject * +memoryview_tolist(PyMemoryViewObject *self, PyObject *Py_UNUSED(ignored)) +{ + return memoryview_tolist_impl(self); +} + +PyDoc_STRVAR(memoryview_tobytes__doc__, +"tobytes($self, /, order=\'C\')\n" +"--\n" +"\n" +"Return the data in the buffer as a byte string.\n" +"\n" +"Order can be {\'C\', \'F\', \'A\'}. When order is \'C\' or \'F\', the data of the\n" +"original array is converted to C or Fortran order. For contiguous views,\n" +"\'A\' returns an exact copy of the physical memory. In particular, in-memory\n" +"Fortran order is preserved. For non-contiguous views, the data is converted\n" +"to C first. order=None is the same as order=\'C\'."); + +#define MEMORYVIEW_TOBYTES_METHODDEF \ + {"tobytes", (PyCFunction)(void(*)(void))memoryview_tobytes, METH_FASTCALL|METH_KEYWORDS, memoryview_tobytes__doc__}, + +static PyObject * +memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order); + +static PyObject * +memoryview_tobytes(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"order", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "tobytes", 0}; + PyObject *argsbuf[1]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + const char *order = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 1, 0, argsbuf); + if (!args) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (args[0] == Py_None) { + order = NULL; + } + else if (PyUnicode_Check(args[0])) { + Py_ssize_t order_length; + order = PyUnicode_AsUTF8AndSize(args[0], &order_length); + if (order == NULL) { + goto exit; + } + if (strlen(order) != (size_t)order_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + } + else { + _PyArg_BadArgument("tobytes", "argument 'order'", "str or None", args[0]); + goto exit; + } +skip_optional_pos: + return_value = memoryview_tobytes_impl(self, order); + +exit: + return return_value; +} + PyDoc_STRVAR(memoryview_hex__doc__, "hex($self, /, sep=<unrepresentable>, bytes_per_sep=1)\n" "--\n" @@ -56,11 +248,6 @@ memoryview_hex(PyMemoryViewObject *self, PyObject *const *args, Py_ssize_t nargs goto skip_optional_pos; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } bytes_per_sep = _PyLong_AsInt(args[1]); if (bytes_per_sep == -1 && PyErr_Occurred()) { goto exit; @@ -71,4 +258,4 @@ skip_optional_pos: exit: return return_value; } -/*[clinic end generated code: output=ee265a73f68b0077 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=1b879bb934d18c66 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/odictobject.c.h b/contrib/tools/python3/src/Objects/clinic/odictobject.c.h index f43bc14ce1..a3ab9ea507 100644 --- a/contrib/tools/python3/src/Objects/clinic/odictobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/odictobject.c.h @@ -83,6 +83,49 @@ exit: return return_value; } +PyDoc_STRVAR(OrderedDict_pop__doc__, +"pop($self, /, key, default=<unrepresentable>)\n" +"--\n" +"\n" +"od.pop(key[,default]) -> v, remove specified key and return the corresponding value.\n" +"\n" +"If the key is not found, return the default if given; otherwise,\n" +"raise a KeyError."); + +#define ORDEREDDICT_POP_METHODDEF \ + {"pop", (PyCFunction)(void(*)(void))OrderedDict_pop, METH_FASTCALL|METH_KEYWORDS, OrderedDict_pop__doc__}, + +static PyObject * +OrderedDict_pop_impl(PyODictObject *self, PyObject *key, + PyObject *default_value); + +static PyObject * +OrderedDict_pop(PyODictObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"key", "default", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "pop", 0}; + PyObject *argsbuf[2]; + Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 1; + PyObject *key; + PyObject *default_value = NULL; + + args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 2, 0, argsbuf); + if (!args) { + goto exit; + } + key = args[0]; + if (!noptargs) { + goto skip_optional_pos; + } + default_value = args[1]; +skip_optional_pos: + return_value = OrderedDict_pop_impl(self, key, default_value); + +exit: + return return_value; +} + PyDoc_STRVAR(OrderedDict_popitem__doc__, "popitem($self, /, last=True)\n" "--\n" @@ -168,4 +211,4 @@ skip_optional_pos: exit: return return_value; } -/*[clinic end generated code: output=8eb1296df9142908 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e0afaad5b4bb47fe input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/typeobject.c.h b/contrib/tools/python3/src/Objects/clinic/typeobject.c.h index 357eb44b12..8c70d76d91 100644 --- a/contrib/tools/python3/src/Objects/clinic/typeobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/typeobject.c.h @@ -166,11 +166,6 @@ object___reduce_ex__(PyObject *self, PyObject *arg) PyObject *return_value = NULL; int protocol; - if (PyFloat_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } protocol = _PyLong_AsInt(arg); if (protocol == -1 && PyErr_Occurred()) { goto exit; @@ -248,4 +243,4 @@ object___dir__(PyObject *self, PyObject *Py_UNUSED(ignored)) { return object___dir___impl(self); } -/*[clinic end generated code: output=7a6d272d282308f3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=b4fb62939b08baf9 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/clinic/unicodeobject.c.h b/contrib/tools/python3/src/Objects/clinic/unicodeobject.c.h index cf81df4af6..9ef8ce2e35 100644 --- a/contrib/tools/python3/src/Objects/clinic/unicodeobject.c.h +++ b/contrib/tools/python3/src/Objects/clinic/unicodeobject.c.h @@ -86,14 +86,9 @@ unicode_center(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("center", nargs, 1, 2)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -224,11 +219,6 @@ unicode_expandtabs(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyOb if (!noptargs) { goto skip_optional_pos; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } tabsize = _PyLong_AsInt(args[0]); if (tabsize == -1 && PyErr_Occurred()) { goto exit; @@ -530,14 +520,9 @@ unicode_ljust(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("ljust", nargs, 1, 2)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -730,14 +715,9 @@ unicode_replace(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (nargs < 3) { goto skip_optional; } - if (PyFloat_Check(args[2])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[2]); + PyObject *iobj = _PyNumber_Index(args[2]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -849,14 +829,9 @@ unicode_rjust(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("rjust", nargs, 1, 2)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -923,14 +898,9 @@ unicode_split(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject goto skip_optional_pos; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[1]); + PyObject *iobj = _PyNumber_Index(args[1]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -1025,14 +995,9 @@ unicode_rsplit(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject goto skip_optional_pos; } } - if (PyFloat_Check(args[1])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[1]); + PyObject *iobj = _PyNumber_Index(args[1]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -1081,11 +1046,6 @@ unicode_splitlines(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyOb if (!noptargs) { goto skip_optional_pos; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } keepends = _PyLong_AsInt(args[0]); if (keepends == -1 && PyErr_Occurred()) { goto exit; @@ -1231,14 +1191,9 @@ unicode_zfill(PyObject *self, PyObject *arg) PyObject *return_value = NULL; Py_ssize_t width; - if (PyFloat_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(arg); + PyObject *iobj = _PyNumber_Index(arg); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -1303,4 +1258,73 @@ unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) { return unicode_sizeof_impl(self); } -/*[clinic end generated code: output=b91233f3722643be input=a9049054013a1b77]*/ + +static PyObject * +unicode_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, + const char *errors); + +static PyObject * +unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"object", "encoding", "errors", NULL}; + static _PyArg_Parser _parser = {NULL, _keywords, "str", 0}; + PyObject *argsbuf[3]; + PyObject * const *fastargs; + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + Py_ssize_t noptargs = nargs + (kwargs ? PyDict_GET_SIZE(kwargs) : 0) - 0; + PyObject *x = NULL; + const char *encoding = NULL; + const char *errors = NULL; + + fastargs = _PyArg_UnpackKeywords(_PyTuple_CAST(args)->ob_item, nargs, kwargs, NULL, &_parser, 0, 3, 0, argsbuf); + if (!fastargs) { + goto exit; + } + if (!noptargs) { + goto skip_optional_pos; + } + if (fastargs[0]) { + x = fastargs[0]; + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (fastargs[1]) { + if (!PyUnicode_Check(fastargs[1])) { + _PyArg_BadArgument("str", "argument 'encoding'", "str", fastargs[1]); + goto exit; + } + Py_ssize_t encoding_length; + encoding = PyUnicode_AsUTF8AndSize(fastargs[1], &encoding_length); + if (encoding == NULL) { + goto exit; + } + if (strlen(encoding) != (size_t)encoding_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } + if (!--noptargs) { + goto skip_optional_pos; + } + } + if (!PyUnicode_Check(fastargs[2])) { + _PyArg_BadArgument("str", "argument 'errors'", "str", fastargs[2]); + goto exit; + } + Py_ssize_t errors_length; + errors = PyUnicode_AsUTF8AndSize(fastargs[2], &errors_length); + if (errors == NULL) { + goto exit; + } + if (strlen(errors) != (size_t)errors_length) { + PyErr_SetString(PyExc_ValueError, "embedded null character"); + goto exit; + } +skip_optional_pos: + return_value = unicode_new_impl(type, x, encoding, errors); + +exit: + return return_value; +} +/*[clinic end generated code: output=f10cf85d3935b3b7 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/codeobject.c b/contrib/tools/python3/src/Objects/codeobject.c index cb4fb68124..c9f922707e 100644 --- a/contrib/tools/python3/src/Objects/codeobject.c +++ b/contrib/tools/python3/src/Objects/codeobject.c @@ -4,10 +4,10 @@ #include "code.h" #include "opcode.h" #include "structmember.h" // PyMemberDef -#include "pycore_code.h" +#include "pycore_code.h" // _PyOpcache #include "pycore_interp.h" // PyInterpreterState.co_extra_freefuncs #include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "pycore_tupleobject.h" +#include "pycore_tuple.h" // _PyTuple_ITEMS() #include "clinic/codeobject.c.h" /* Holder for co_extra information */ @@ -119,7 +119,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, - PyObject *lnotab) + PyObject *linetable) { PyCodeObject *co; Py_ssize_t *cell2arg = NULL; @@ -137,7 +137,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, cellvars == NULL || !PyTuple_Check(cellvars) || name == NULL || !PyUnicode_Check(name) || filename == NULL || !PyUnicode_Check(filename) || - lnotab == NULL || !PyBytes_Check(lnotab)) { + linetable == NULL || !PyBytes_Check(linetable)) { PyErr_BadInternalCall(); return NULL; } @@ -213,7 +213,7 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, PyObject *arg = PyTuple_GET_ITEM(varnames, j); int cmp = PyUnicode_Compare(cell, arg); if (cmp == -1 && PyErr_Occurred()) { - PyMem_FREE(cell2arg); + PyMem_Free(cell2arg); return NULL; } if (cmp == 0) { @@ -224,14 +224,14 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, } } if (!used_cell2arg) { - PyMem_FREE(cell2arg); + PyMem_Free(cell2arg); cell2arg = NULL; } } co = PyObject_New(PyCodeObject, &PyCode_Type); if (co == NULL) { if (cell2arg) - PyMem_FREE(cell2arg); + PyMem_Free(cell2arg); return NULL; } co->co_argcount = argcount; @@ -258,8 +258,8 @@ PyCode_NewWithPosOnlyArgs(int argcount, int posonlyargcount, int kwonlyargcount, Py_INCREF(name); co->co_name = name; co->co_firstlineno = firstlineno; - Py_INCREF(lnotab); - co->co_lnotab = lnotab; + Py_INCREF(linetable); + co->co_linetable = linetable; co->co_zombieframe = NULL; co->co_weakreflist = NULL; co->co_extra = NULL; @@ -277,12 +277,12 @@ PyCode_New(int argcount, int kwonlyargcount, PyObject *code, PyObject *consts, PyObject *names, PyObject *varnames, PyObject *freevars, PyObject *cellvars, PyObject *filename, PyObject *name, int firstlineno, - PyObject *lnotab) + PyObject *linetable) { return PyCode_NewWithPosOnlyArgs(argcount, 0, kwonlyargcount, nlocals, stacksize, flags, code, consts, names, varnames, freevars, cellvars, filename, - name, firstlineno, lnotab); + name, firstlineno, linetable); } int @@ -294,15 +294,15 @@ _PyCode_InitOpcache(PyCodeObject *co) return -1; } - _Py_CODEUNIT *opcodes = (_Py_CODEUNIT*)PyBytes_AS_STRING(co->co_code); + const _Py_CODEUNIT *opcodes = (_Py_CODEUNIT*)PyBytes_AS_STRING(co->co_code); Py_ssize_t opts = 0; for (Py_ssize_t i = 0; i < co_size;) { unsigned char opcode = _Py_OPCODE(opcodes[i]); i++; // 'i' is now aligned to (next_instr - first_instr) - // TODO: LOAD_METHOD, LOAD_ATTR - if (opcode == LOAD_GLOBAL) { + // TODO: LOAD_METHOD + if (opcode == LOAD_GLOBAL || opcode == LOAD_ATTR) { opts++; co->co_opcache_map[i] = (unsigned char)opts; if (opts > 254) { @@ -314,12 +314,12 @@ _PyCode_InitOpcache(PyCodeObject *co) if (opts) { co->co_opcache = (_PyOpcache *)PyMem_Calloc(opts, sizeof(_PyOpcache)); if (co->co_opcache == NULL) { - PyMem_FREE(co->co_opcache_map); + PyMem_Free(co->co_opcache_map); return -1; } } else { - PyMem_FREE(co->co_opcache_map); + PyMem_Free(co->co_opcache_map); co->co_opcache_map = NULL; co->co_opcache = NULL; } @@ -369,7 +369,7 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno) filename_ob, /* filename */ funcname_ob, /* name */ firstlineno, /* firstlineno */ - emptystring /* lnotab */ + emptystring /* linetable */ ); failed: @@ -395,11 +395,89 @@ static PyMemberDef code_memberlist[] = { {"co_cellvars", T_OBJECT, OFF(co_cellvars), READONLY}, {"co_filename", T_OBJECT, OFF(co_filename), READONLY}, {"co_name", T_OBJECT, OFF(co_name), READONLY}, - {"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY}, - {"co_lnotab", T_OBJECT, OFF(co_lnotab), READONLY}, + {"co_firstlineno", T_INT, OFF(co_firstlineno), READONLY}, + {"co_linetable", T_OBJECT, OFF(co_linetable), READONLY}, {NULL} /* Sentinel */ }; +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; + } + unsigned char *lnotab = (unsigned char *) PyBytes_AS_STRING(*bytes); + lnotab += *offset; + *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 * +code_getlnotab(PyCodeObject *code, void *closure) +{ + PyCodeAddressRange bounds; + PyObject *bytes; + int table_offset = 0; + int code_offset = 0; + int line = code->co_firstlineno; + bytes = PyBytes_FromStringAndSize(NULL, 64); + if (bytes == NULL) { + return NULL; + } + _PyCode_InitAddressRange(code, &bounds); + while (PyLineTable_NextAddressRange(&bounds)) { + if (bounds.opaque.computed_line != line) { + int bdelta = bounds.ar_start - code_offset; + int ldelta = bounds.opaque.computed_line - line; + if (!emit_delta(&bytes, bdelta, ldelta, &table_offset)) { + Py_DECREF(bytes); + return NULL; + } + code_offset = bounds.ar_start; + line = bounds.opaque.computed_line; + } + } + _PyBytes_Resize(&bytes, table_offset); + return bytes; +} + + +static PyGetSetDef code_getsetlist[] = { + {"co_lnotab", (getter)code_getlnotab, NULL, NULL}, + {0} +}; + + /* Helper for code_new: 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. */ @@ -442,46 +520,45 @@ validate_and_copy_tuple(PyObject *tup) return newtuple; } -PyDoc_STRVAR(code_doc, -"code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n\ - flags, codestring, constants, names, varnames, filename, name,\n\ - firstlineno, lnotab[, freevars[, cellvars]])\n\ -\n\ -Create a code object. Not for the faint of heart."); +/*[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 + firstlineno: int + linetable: object(subclass_of="&PyBytes_Type") + 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]*/ static PyObject * -code_new(PyTypeObject *type, PyObject *args, PyObject *kw) +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, + int firstlineno, PyObject *linetable, PyObject *freevars, + PyObject *cellvars) +/*[clinic end generated code: output=42c1839b082ba293 input=0ec80da632b99f57]*/ { - int argcount; - int posonlyargcount; - int kwonlyargcount; - int nlocals; - int stacksize; - int flags; PyObject *co = NULL; - PyObject *code; - PyObject *consts; - PyObject *names, *ournames = NULL; - PyObject *varnames, *ourvarnames = NULL; - PyObject *freevars = NULL, *ourfreevars = NULL; - PyObject *cellvars = NULL, *ourcellvars = NULL; - PyObject *filename; - PyObject *name; - int firstlineno; - PyObject *lnotab; - - if (!PyArg_ParseTuple(args, "iiiiiiSO!O!O!UUiS|O!O!:code", - &argcount, &posonlyargcount, &kwonlyargcount, - &nlocals, &stacksize, &flags, - &code, - &PyTuple_Type, &consts, - &PyTuple_Type, &names, - &PyTuple_Type, &varnames, - &filename, &name, - &firstlineno, &lnotab, - &PyTuple_Type, &freevars, - &PyTuple_Type, &cellvars)) - return NULL; + PyObject *ournames = NULL; + PyObject *ourvarnames = NULL; + PyObject *ourfreevars = NULL; + PyObject *ourcellvars = NULL; if (PySys_Audit("code.__new__", "OOOiiiiii", code, filename, name, argcount, posonlyargcount, @@ -541,7 +618,7 @@ code_new(PyTypeObject *type, PyObject *args, PyObject *kw) code, consts, ournames, ourvarnames, ourfreevars, ourcellvars, filename, - name, firstlineno, lnotab); + name, firstlineno, linetable); cleanup: Py_XDECREF(ournames); Py_XDECREF(ourvarnames); @@ -554,10 +631,10 @@ static void code_dealloc(PyCodeObject *co) { if (co->co_opcache != NULL) { - PyMem_FREE(co->co_opcache); + PyMem_Free(co->co_opcache); } if (co->co_opcache_map != NULL) { - PyMem_FREE(co->co_opcache_map); + PyMem_Free(co->co_opcache_map); } co->co_opcache_flag = 0; co->co_opcache_size = 0; @@ -585,14 +662,14 @@ code_dealloc(PyCodeObject *co) Py_XDECREF(co->co_cellvars); Py_XDECREF(co->co_filename); Py_XDECREF(co->co_name); - Py_XDECREF(co->co_lnotab); + Py_XDECREF(co->co_linetable); if (co->co_cell2arg != NULL) - PyMem_FREE(co->co_cell2arg); + PyMem_Free(co->co_cell2arg); if (co->co_zombieframe != NULL) PyObject_GC_Del(co->co_zombieframe); if (co->co_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject*)co); - PyObject_DEL(co); + PyObject_Free(co); } static PyObject * @@ -637,7 +714,7 @@ code.replace co_cellvars: object(subclass_of="&PyTuple_Type", c_default="self->co_cellvars") = None co_filename: unicode(c_default="self->co_filename") = None co_name: unicode(c_default="self->co_name") = None - co_lnotab: PyBytesObject(c_default="(PyBytesObject *)self->co_lnotab") = None + co_linetable: PyBytesObject(c_default="(PyBytesObject *)self->co_linetable") = None Return a copy of the code object with new values for the specified fields. [clinic start generated code]*/ @@ -650,8 +727,8 @@ code_replace_impl(PyCodeObject *self, int co_argcount, PyObject *co_consts, PyObject *co_names, PyObject *co_varnames, PyObject *co_freevars, PyObject *co_cellvars, PyObject *co_filename, - PyObject *co_name, PyBytesObject *co_lnotab) -/*[clinic end generated code: output=25c8e303913bcace input=d9051bc8f24e6b28]*/ + PyObject *co_name, PyBytesObject *co_linetable) +/*[clinic end generated code: output=50d77e668d3b449b input=a5f997b173d7f636]*/ { #define CHECK_INT_ARG(ARG) \ if (ARG < 0) { \ @@ -681,7 +758,7 @@ code_replace_impl(PyCodeObject *self, int co_argcount, co_argcount, co_posonlyargcount, co_kwonlyargcount, co_nlocals, co_stacksize, co_flags, (PyObject*)co_code, co_consts, co_names, co_varnames, co_freevars, co_cellvars, co_filename, co_name, - co_firstlineno, (PyObject*)co_lnotab); + co_firstlineno, (PyObject*)co_linetable); } static PyObject * @@ -934,10 +1011,188 @@ code_hash(PyCodeObject *co) return h; } +typedef struct { + PyObject_HEAD + PyCodeObject *li_code; + PyCodeAddressRange li_line; + char *li_end; +} lineiterator; + + +static void +lineiter_dealloc(lineiterator *li) +{ + Py_DECREF(li->li_code); + Py_TYPE(li)->tp_free(li); +} + +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; + } + 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; +} + +static PyTypeObject LineIterator = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "line_iterator", /* tp_name */ + sizeof(lineiterator), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)lineiter_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)lineiter_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + PyObject_Del, /* tp_free */ +}; + +static PyObject * +code_linesiterator(PyCodeObject *code, PyObject *Py_UNUSED(args)) +{ + lineiterator *li = (lineiterator *)PyType_GenericAlloc(&LineIterator, 0); + if (li == NULL) { + return NULL; + } + Py_INCREF(code); + li->li_code = code; + _PyCode_InitAddressRange(code, &li->li_line); + return (PyObject *)li; +} + +static void +retreat(PyCodeAddressRange *bounds) +{ + int ldelta = ((signed char *)bounds->opaque.lo_next)[-1]; + if (ldelta == -128) { + ldelta = 0; + } + bounds->opaque.computed_line -= ldelta; + bounds->opaque.lo_next -= 2; + bounds->ar_end = bounds->ar_start; + bounds->ar_start -= ((unsigned char *)bounds->opaque.lo_next)[-2]; + ldelta = ((signed char *)bounds->opaque.lo_next)[-1]; + if (ldelta == -128) { + bounds->ar_line = -1; + } + else { + bounds->ar_line = bounds->opaque.computed_line; + } +} + +static void +advance(PyCodeAddressRange *bounds) +{ + bounds->ar_start = bounds->ar_end; + int delta = ((unsigned char *)bounds->opaque.lo_next)[0]; + bounds->ar_end += delta; + int ldelta = ((signed char *)bounds->opaque.lo_next)[1]; + bounds->opaque.lo_next += 2; + if (ldelta == -128) { + bounds->ar_line = -1; + } + else { + bounds->opaque.computed_line += ldelta; + bounds->ar_line = bounds->opaque.computed_line; + } +} + +static inline int +at_end(PyCodeAddressRange *bounds) { + return bounds->opaque.lo_next >= bounds->opaque.limit; +} + +int +PyLineTable_PreviousAddressRange(PyCodeAddressRange *range) +{ + if (range->ar_start <= 0) { + return 0; + } + retreat(range); + while (range->ar_start == range->ar_end) { + assert(range->ar_start > 0); + retreat(range); + } + return 1; +} + +int +PyLineTable_NextAddressRange(PyCodeAddressRange *range) +{ + if (at_end(range)) { + return 0; + } + advance(range); + while (range->ar_start == range->ar_end && !at_end(range)) { + assert(!at_end(range)); + advance(range); + } + return 1; +} + + /* 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}, CODE_REPLACE_METHODDEF {NULL, NULL} /* sentinel */ }; @@ -963,7 +1218,7 @@ PyTypeObject PyCode_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ - code_doc, /* tp_doc */ + code_new__doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ code_richcompare, /* tp_richcompare */ @@ -972,7 +1227,7 @@ PyTypeObject PyCode_Type = { 0, /* tp_iternext */ code_methods, /* tp_methods */ code_memberlist, /* tp_members */ - 0, /* tp_getset */ + code_getsetlist, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ @@ -983,78 +1238,58 @@ PyTypeObject PyCode_Type = { code_new, /* tp_new */ }; -/* Use co_lnotab to compute the line number from a bytecode index, addrq. See +/* Use co_linetable to compute the line number from a bytecode index, addrq. See lnotab_notes.txt for the details of the lnotab representation. */ int PyCode_Addr2Line(PyCodeObject *co, int addrq) { - Py_ssize_t size = PyBytes_Size(co->co_lnotab) / 2; - unsigned char *p = (unsigned char*)PyBytes_AsString(co->co_lnotab); - int line = co->co_firstlineno; - int addr = 0; - while (--size >= 0) { - addr += *p++; - if (addr > addrq) - break; - line += (signed char)*p; - p++; - } - return line; + if (addrq < 0) { + return co->co_firstlineno; + } + assert(addrq >= 0 && addrq < PyBytes_GET_SIZE(co->co_code)); + PyCodeAddressRange bounds; + _PyCode_InitAddressRange(co, &bounds); + return _PyCode_CheckLineNumber(addrq, &bounds); +} + +void +PyLineTable_InitAddressRange(const char *linetable, Py_ssize_t length, int firstlineno, PyCodeAddressRange *range) +{ + range->opaque.lo_next = linetable; + range->opaque.limit = range->opaque.lo_next + length; + range->ar_start = -1; + range->ar_end = 0; + range->opaque.computed_line = firstlineno; + range->ar_line = -1; +} + +int +_PyCode_InitAddressRange(PyCodeObject* co, PyCodeAddressRange *bounds) +{ + const char *linetable = PyBytes_AS_STRING(co->co_linetable); + Py_ssize_t length = PyBytes_GET_SIZE(co->co_linetable); + PyLineTable_InitAddressRange(linetable, length, co->co_firstlineno, bounds); + 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. */ + the same line as lasti. Return the number of that line, or -1 if lasti is out of bounds. */ int -_PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds) +_PyCode_CheckLineNumber(int lasti, PyCodeAddressRange *bounds) { - Py_ssize_t size; - int addr, line; - unsigned char* p; - - p = (unsigned char*)PyBytes_AS_STRING(co->co_lnotab); - size = PyBytes_GET_SIZE(co->co_lnotab) / 2; - - addr = 0; - line = co->co_firstlineno; - assert(line > 0); - - /* possible optimization: if f->f_lasti == instr_ub - (likely to be a common case) then we already know - instr_lb -- if we stored the matching value of p - somewhere we could skip the first while loop. */ - - /* See lnotab_notes.txt for the description of - co_lnotab. A point to remember: increments to p - come in (addr, line) pairs. */ - - bounds->ap_lower = 0; - while (size > 0) { - if (addr + *p > lasti) - break; - addr += *p++; - if ((signed char)*p) - bounds->ap_lower = addr; - line += (signed char)*p; - p++; - --size; - } - - if (size > 0) { - while (--size >= 0) { - addr += *p++; - if ((signed char)*p) - break; - p++; + while (bounds->ar_end <= lasti) { + if (!PyLineTable_NextAddressRange(bounds)) { + return -1; } - bounds->ap_upper = addr; } - else { - bounds->ap_upper = INT_MAX; + while (bounds->ar_start > lasti) { + if (!PyLineTable_PreviousAddressRange(bounds)) { + return -1; + } } - - return line; + return bounds->ar_line; } diff --git a/contrib/tools/python3/src/Objects/complexobject.c b/contrib/tools/python3/src/Objects/complexobject.c index e09cc15fe8..3e479497cf 100644 --- a/contrib/tools/python3/src/Objects/complexobject.c +++ b/contrib/tools/python3/src/Objects/complexobject.c @@ -6,8 +6,11 @@ /* Submitted by Jim Hugunin */ #include "Python.h" +#include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_object.h" // _PyObject_Init() #include "structmember.h" // PyMemberDef + /*[clinic input] class complex "PyComplexObject *" "&PyComplex_Type" [clinic start generated code]*/ @@ -222,13 +225,12 @@ complex_subtype_from_c_complex(PyTypeObject *type, Py_complex cval) PyObject * PyComplex_FromCComplex(Py_complex cval) { - PyComplexObject *op; - /* Inline PyObject_New */ - op = (PyComplexObject *) PyObject_MALLOC(sizeof(PyComplexObject)); - if (op == NULL) + PyComplexObject *op = PyObject_Malloc(sizeof(PyComplexObject)); + if (op == NULL) { return PyErr_NoMemory(); - (void)PyObject_INIT(op, &PyComplex_Type); + } + _PyObject_Init((PyObject*)op, &PyComplex_Type); op->cval = cval; return (PyObject *) op; } @@ -403,10 +405,10 @@ static Py_hash_t complex_hash(PyComplexObject *v) { Py_uhash_t hashreal, hashimag, combined; - hashreal = (Py_uhash_t)_Py_HashDouble(v->cval.real); + hashreal = (Py_uhash_t)_Py_HashDouble((PyObject *) v, v->cval.real); if (hashreal == (Py_uhash_t)-1) return -1; - hashimag = (Py_uhash_t)_Py_HashDouble(v->cval.imag); + hashimag = (Py_uhash_t)_Py_HashDouble((PyObject *)v, v->cval.imag); if (hashimag == (Py_uhash_t)-1) return -1; /* Note: if the imaginary part is 0, hashimag is 0 now, @@ -502,23 +504,6 @@ complex_div(PyObject *v, PyObject *w) } static PyObject * -complex_remainder(PyObject *v, PyObject *w) -{ - PyErr_SetString(PyExc_TypeError, - "can't mod complex numbers."); - return NULL; -} - - -static PyObject * -complex_divmod(PyObject *v, PyObject *w) -{ - PyErr_SetString(PyExc_TypeError, - "can't take floor or mod of complex number."); - return NULL; -} - -static PyObject * complex_pow(PyObject *v, PyObject *w, PyObject *z) { Py_complex p; @@ -555,14 +540,6 @@ complex_pow(PyObject *v, PyObject *w, PyObject *z) } static PyObject * -complex_int_div(PyObject *v, PyObject *w) -{ - PyErr_SetString(PyExc_TypeError, - "can't take floor of complex number."); - return NULL; -} - -static PyObject * complex_neg(PyComplexObject *v) { Py_complex neg; @@ -660,62 +637,54 @@ Unimplemented: Py_RETURN_NOTIMPLEMENTED; } -static PyObject * -complex_int(PyObject *v) -{ - PyErr_SetString(PyExc_TypeError, - "can't convert complex to int"); - return NULL; -} +/*[clinic input] +complex.conjugate -static PyObject * -complex_float(PyObject *v) -{ - PyErr_SetString(PyExc_TypeError, - "can't convert complex to float"); - return NULL; -} +Return the complex conjugate of its argument. (3-4j).conjugate() == 3+4j. +[clinic start generated code]*/ static PyObject * -complex_conjugate(PyObject *self, PyObject *Py_UNUSED(ignored)) +complex_conjugate_impl(PyComplexObject *self) +/*[clinic end generated code: output=5059ef162edfc68e input=5fea33e9747ec2c4]*/ { - Py_complex c; - c = ((PyComplexObject *)self)->cval; + Py_complex c = self->cval; c.imag = -c.imag; return PyComplex_FromCComplex(c); } -PyDoc_STRVAR(complex_conjugate_doc, -"complex.conjugate() -> complex\n" -"\n" -"Return the complex conjugate of its argument. (3-4j).conjugate() == 3+4j."); +/*[clinic input] +complex.__getnewargs__ + +[clinic start generated code]*/ static PyObject * -complex_getnewargs(PyComplexObject *v, PyObject *Py_UNUSED(ignored)) +complex___getnewargs___impl(PyComplexObject *self) +/*[clinic end generated code: output=689b8206e8728934 input=539543e0a50533d7]*/ { - Py_complex c = v->cval; + Py_complex c = self->cval; return Py_BuildValue("(dd)", c.real, c.imag); } -PyDoc_STRVAR(complex__format__doc, -"complex.__format__() -> str\n" -"\n" -"Convert to a string according to format_spec."); + +/*[clinic input] +complex.__format__ + + format_spec: unicode + / + +Convert to a string according to format_spec. +[clinic start generated code]*/ static PyObject * -complex__format__(PyObject* self, PyObject* args) +complex___format___impl(PyComplexObject *self, PyObject *format_spec) +/*[clinic end generated code: output=bfcb60df24cafea0 input=014ef5488acbe1d5]*/ { - PyObject *format_spec; _PyUnicodeWriter writer; int ret; - - if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) - return NULL; - _PyUnicodeWriter_Init(&writer); ret = _PyComplex_FormatAdvancedWriter( &writer, - self, + (PyObject *)self, format_spec, 0, PyUnicode_GET_LENGTH(format_spec)); if (ret == -1) { _PyUnicodeWriter_Dealloc(&writer); @@ -725,11 +694,9 @@ complex__format__(PyObject* self, PyObject* args) } static PyMethodDef complex_methods[] = { - {"conjugate", (PyCFunction)complex_conjugate, METH_NOARGS, - complex_conjugate_doc}, - {"__getnewargs__", (PyCFunction)complex_getnewargs, METH_NOARGS}, - {"__format__", (PyCFunction)complex__format__, - METH_VARARGS, complex__format__doc}, + COMPLEX_CONJUGATE_METHODDEF + COMPLEX___GETNEWARGS___METHODDEF + COMPLEX___FORMAT___METHODDEF {NULL, NULL} /* sentinel */ }; @@ -897,7 +864,7 @@ complex_subtype_from_string(PyTypeObject *type, PyObject *v) /*[clinic input] @classmethod complex.__new__ as complex_new - real as r: object(c_default="_PyLong_Zero") = 0 + real as r: object(c_default="NULL") = 0 imag as i: object(c_default="NULL") = 0 Create a complex number from a real part and an optional imaginary part. @@ -907,7 +874,7 @@ This is equivalent to (real + imag*1j) where imag defaults to 0. static PyObject * complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) -/*[clinic end generated code: output=b6c7dd577b537dc1 input=6f6b0bedba29bcb5]*/ +/*[clinic end generated code: output=b6c7dd577b537dc1 input=f4c667f2596d4fd1]*/ { PyObject *tmp; PyNumberMethods *nbr, *nbi = NULL; @@ -916,6 +883,10 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) int cr_is_complex = 0; int ci_is_complex = 0; + if (r == NULL) { + r = _PyLong_GetZero(); + } + /* Special-case for a single argument when type(arg) is complex. */ if (PyComplex_CheckExact(r) && i == NULL && type == &PyComplex_Type) { @@ -952,7 +923,9 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) } nbr = Py_TYPE(r)->tp_as_number; - if (nbr == NULL || (nbr->nb_float == NULL && nbr->nb_index == NULL)) { + if (nbr == NULL || + (nbr->nb_float == NULL && nbr->nb_index == NULL && !PyComplex_Check(r))) + { PyErr_Format(PyExc_TypeError, "complex() first argument must be a string or a number, " "not '%.200s'", @@ -964,7 +937,9 @@ complex_new_impl(PyTypeObject *type, PyObject *r, PyObject *i) } if (i != NULL) { nbi = Py_TYPE(i)->tp_as_number; - if (nbi == NULL || (nbi->nb_float == NULL && nbi->nb_index == NULL)) { + if (nbi == NULL || + (nbi->nb_float == NULL && nbi->nb_index == NULL && !PyComplex_Check(i))) + { PyErr_Format(PyExc_TypeError, "complex() second argument must be a number, " "not '%.200s'", @@ -1043,8 +1018,8 @@ static PyNumberMethods complex_as_number = { (binaryfunc)complex_add, /* nb_add */ (binaryfunc)complex_sub, /* nb_subtract */ (binaryfunc)complex_mul, /* nb_multiply */ - (binaryfunc)complex_remainder, /* nb_remainder */ - (binaryfunc)complex_divmod, /* nb_divmod */ + 0, /* nb_remainder */ + 0, /* nb_divmod */ (ternaryfunc)complex_pow, /* nb_power */ (unaryfunc)complex_neg, /* nb_negative */ (unaryfunc)complex_pos, /* nb_positive */ @@ -1056,9 +1031,9 @@ static PyNumberMethods complex_as_number = { 0, /* nb_and */ 0, /* nb_xor */ 0, /* nb_or */ - complex_int, /* nb_int */ + 0, /* nb_int */ 0, /* nb_reserved */ - complex_float, /* nb_float */ + 0, /* nb_float */ 0, /* nb_inplace_add */ 0, /* nb_inplace_subtract */ 0, /* nb_inplace_multiply*/ @@ -1069,7 +1044,7 @@ static PyNumberMethods complex_as_number = { 0, /* nb_inplace_and */ 0, /* nb_inplace_xor */ 0, /* nb_inplace_or */ - (binaryfunc)complex_int_div, /* nb_floor_divide */ + 0, /* nb_floor_divide */ (binaryfunc)complex_div, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */ diff --git a/contrib/tools/python3/src/Objects/descrobject.c b/contrib/tools/python3/src/Objects/descrobject.c index 00349ab179..09b0f82c69 100644 --- a/contrib/tools/python3/src/Objects/descrobject.c +++ b/contrib/tools/python3/src/Objects/descrobject.c @@ -1,10 +1,10 @@ /* Descriptors -- a new, flexible way to describe attributes */ #include "Python.h" -#include "pycore_ceval.h" // _Py_EnterRecursiveCall() -#include "pycore_object.h" -#include "pycore_pystate.h" // _PyThreadState_GET() -#include "pycore_tupleobject.h" +#include "pycore_ceval.h" // _Py_EnterRecursiveCall() +#include "pycore_object.h" // _PyObject_GC_UNTRACK() +#include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_tuple.h" // _PyTuple_ITEMS() #include "structmember.h" // PyMemberDef _Py_IDENTIFIER(getattr); @@ -132,8 +132,7 @@ static PyObject * method_get(PyMethodDescrObject *descr, PyObject *obj, PyObject *type) { if (obj == NULL) { - Py_INCREF(descr); - return (PyObject *)descr; + return Py_NewRef(descr); } if (descr_check((PyDescrObject *)descr, obj) < 0) { return NULL; @@ -157,14 +156,13 @@ static PyObject * member_get(PyMemberDescrObject *descr, PyObject *obj, PyObject *type) { if (obj == NULL) { - Py_INCREF(descr); - return (PyObject *)descr; + return Py_NewRef(descr); } if (descr_check((PyDescrObject *)descr, obj) < 0) { return NULL; } - if (descr->d_member->flags & READ_RESTRICTED) { + if (descr->d_member->flags & PY_AUDIT_READ) { if (PySys_Audit("object.__getattr__", "Os", obj ? obj : Py_None, descr->d_member->name) < 0) { return NULL; @@ -178,8 +176,7 @@ static PyObject * getset_get(PyGetSetDescrObject *descr, PyObject *obj, PyObject *type) { if (obj == NULL) { - Py_INCREF(descr); - return (PyObject *)descr; + return Py_NewRef(descr); } if (descr_check((PyDescrObject *)descr, obj) < 0) { return NULL; @@ -197,8 +194,7 @@ static PyObject * wrapperdescr_get(PyWrapperDescrObject *descr, PyObject *obj, PyObject *type) { if (obj == NULL) { - Py_INCREF(descr); - return (PyObject *)descr; + return Py_NewRef(descr); } if (descr_check((PyDescrObject *)descr, obj) < 0) { return NULL; @@ -997,6 +993,11 @@ PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *base, void *wrapped) return (PyObject *)descr; } +int +PyDescr_IsData(PyObject *ob) +{ + return Py_TYPE(ob)->tp_descr_set != NULL; +} /* --- mappingproxy: read-only proxy for mappings --- */ @@ -1492,6 +1493,7 @@ typedef struct { PyObject *prop_set; PyObject *prop_del; PyObject *prop_doc; + PyObject *prop_name; int getter_doc; } propertyobject; @@ -1537,10 +1539,33 @@ property_deleter(PyObject *self, PyObject *deleter) } +PyDoc_STRVAR(set_name_doc, + "Method to set name of a property."); + +static PyObject * +property_set_name(PyObject *self, PyObject *args) { + if (PyTuple_GET_SIZE(args) != 2) { + PyErr_Format( + PyExc_TypeError, + "__set_name__() takes 2 positional arguments but %d were given", + PyTuple_GET_SIZE(args)); + return NULL; + } + + propertyobject *prop = (propertyobject *)self; + PyObject *name = PyTuple_GET_ITEM(args, 1); + + Py_XINCREF(name); + Py_XSETREF(prop->prop_name, name); + + Py_RETURN_NONE; +} + static PyMethodDef property_methods[] = { {"getter", property_getter, METH_O, getter_doc}, {"setter", property_setter, METH_O, setter_doc}, {"deleter", property_deleter, METH_O, deleter_doc}, + {"__set_name__", property_set_name, METH_VARARGS, set_name_doc}, {0} }; @@ -1555,6 +1580,7 @@ property_dealloc(PyObject *self) Py_XDECREF(gs->prop_set); Py_XDECREF(gs->prop_del); Py_XDECREF(gs->prop_doc); + Py_XDECREF(gs->prop_name); Py_TYPE(self)->tp_free(self); } @@ -1568,7 +1594,12 @@ property_descr_get(PyObject *self, PyObject *obj, PyObject *type) propertyobject *gs = (propertyobject *)self; if (gs->prop_get == NULL) { - PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); + if (gs->prop_name != NULL) { + PyErr_Format(PyExc_AttributeError, "unreadable attribute %R", gs->prop_name); + } else { + PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); + } + return NULL; } @@ -1586,10 +1617,18 @@ property_descr_set(PyObject *self, PyObject *obj, PyObject *value) else func = gs->prop_set; if (func == NULL) { - PyErr_SetString(PyExc_AttributeError, + if (gs->prop_name != NULL) { + PyErr_Format(PyExc_AttributeError, value == NULL ? - "can't delete attribute" : - "can't set attribute"); + "can't delete attribute %R" : + "can't set attribute %R", + gs->prop_name); + } else { + PyErr_SetString(PyExc_AttributeError, + value == NULL ? + "can't delete attribute" : + "can't set attribute"); + } return -1; } if (value == NULL) @@ -1636,6 +1675,9 @@ property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del) Py_DECREF(type); if (new == NULL) return NULL; + + Py_XINCREF(pold->prop_name); + Py_XSETREF(((propertyobject *) new)->prop_name, pold->prop_name); return new; } @@ -1697,6 +1739,8 @@ property_init_impl(propertyobject *self, PyObject *fget, PyObject *fset, Py_XSETREF(self->prop_set, fset); Py_XSETREF(self->prop_del, fdel); Py_XSETREF(self->prop_doc, doc); + Py_XSETREF(self->prop_name, NULL); + self->getter_doc = 0; /* if no docstring given and the getter has one, use that one */ @@ -1771,6 +1815,7 @@ property_traverse(PyObject *self, visitproc visit, void *arg) Py_VISIT(pp->prop_set); Py_VISIT(pp->prop_del); Py_VISIT(pp->prop_doc); + Py_VISIT(pp->prop_name); return 0; } @@ -1805,7 +1850,8 @@ PyTypeObject PyDictProxy_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_MAPPING, /* tp_flags */ 0, /* tp_doc */ mappingproxy_traverse, /* tp_traverse */ 0, /* tp_clear */ diff --git a/contrib/tools/python3/src/Objects/dictobject.c b/contrib/tools/python3/src/Objects/dictobject.c index 2ae122d323..24973c07b1 100644 --- a/contrib/tools/python3/src/Objects/dictobject.c +++ b/contrib/tools/python3/src/Objects/dictobject.c @@ -111,8 +111,10 @@ converting the dict to the combined table. #define PyDict_MINSIZE 8 #include "Python.h" +#include "pycore_bitutils.h" // _Py_bit_length #include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() -#include "pycore_object.h" +#include "pycore_object.h" // _PyObject_GC_TRACK() +#include "pycore_pyerrors.h" // _PyErr_Fetch() #include "pycore_pystate.h" // _PyThreadState_GET() #include "dict-common.h" #include "stringlib/eq.h" // unicode_eq() @@ -235,7 +237,7 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, static Py_ssize_t lookdict_split(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr); -static int dictresize(PyDictObject *mp, Py_ssize_t minused); +static int dictresize(PyDictObject *mp, Py_ssize_t newsize); static PyObject* dict_iter(PyDictObject *dict); @@ -246,52 +248,54 @@ static uint64_t pydict_global_version = 0; #define DICT_NEXT_VERSION() (++pydict_global_version) -/* Dictionary reuse scheme to save calls to malloc and free */ -#ifndef PyDict_MAXFREELIST -#define PyDict_MAXFREELIST 80 -#endif +#include "clinic/dictobject.c.h" -#if PyDict_MAXFREELIST > 0 -static PyDictObject *free_list[PyDict_MAXFREELIST]; -static int numfree = 0; -static PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST]; -static int numfreekeys = 0; -#endif -#include "clinic/dictobject.c.h" +static struct _Py_dict_state * +get_dict_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->dict_state; +} + void -_PyDict_ClearFreeList(void) +_PyDict_ClearFreeList(PyInterpreterState *interp) { -#if PyDict_MAXFREELIST > 0 - while (numfree) { - PyDictObject *op = free_list[--numfree]; + struct _Py_dict_state *state = &interp->dict_state; + while (state->numfree) { + PyDictObject *op = state->free_list[--state->numfree]; assert(PyDict_CheckExact(op)); PyObject_GC_Del(op); } - while (numfreekeys) { - PyObject_FREE(keys_free_list[--numfreekeys]); + while (state->keys_numfree) { + PyObject_Free(state->keys_free_list[--state->keys_numfree]); } -#endif } -/* Print summary info about the state of the optimized allocator */ + void -_PyDict_DebugMallocStats(FILE *out) +_PyDict_Fini(PyInterpreterState *interp) { -#if PyDict_MAXFREELIST > 0 - _PyDebugAllocatorStats(out, - "free PyDictObject", numfree, sizeof(PyDictObject)); + _PyDict_ClearFreeList(interp); +#ifdef Py_DEBUG + struct _Py_dict_state *state = &interp->dict_state; + state->numfree = -1; + state->keys_numfree = -1; #endif } +/* Print summary info about the state of the optimized allocator */ void -_PyDict_Fini(void) +_PyDict_DebugMallocStats(FILE *out) { - _PyDict_ClearFreeList(); + struct _Py_dict_state *state = get_dict_state(); + _PyDebugAllocatorStats(out, "free PyDictObject", + state->numfree, sizeof(PyDictObject)); } + #define DK_SIZE(dk) ((dk)->dk_size) #if SIZEOF_VOID_P > 4 #define DK_IXSIZE(dk) \ @@ -408,18 +412,40 @@ dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) */ #define USABLE_FRACTION(n) (((n) << 1)/3) -/* ESTIMATE_SIZE is reverse function of USABLE_FRACTION. +/* Find the smallest dk_size >= minsize. */ +static inline Py_ssize_t +calculate_keysize(Py_ssize_t minsize) +{ +#if SIZEOF_LONG == SIZEOF_SIZE_T + minsize = (minsize | PyDict_MINSIZE) - 1; + return 1LL << _Py_bit_length(minsize | (PyDict_MINSIZE-1)); +#elif defined(_MSC_VER) + // On 64bit Windows, sizeof(long) == 4. + minsize = (minsize | PyDict_MINSIZE) - 1; + unsigned long msb; + _BitScanReverse64(&msb, (uint64_t)minsize); + return 1LL << (msb + 1); +#else + Py_ssize_t size; + for (size = PyDict_MINSIZE; + size < minsize && size > 0; + size <<= 1) + ; + return size; +#endif +} + +/* estimate_keysize is reverse function of USABLE_FRACTION. + * * This can be used to reserve enough size to insert n entries without * resizing. */ -#define ESTIMATE_SIZE(n) (((n)*3+1) >> 1) +static inline Py_ssize_t +estimate_keysize(Py_ssize_t n) +{ + return calculate_keysize((n*3 + 1) / 2); +} -/* Alternative fraction that is otherwise close enough to 2n/3 to make - * little difference. 8 * 2/3 == 8 * 5/8 == 5. 16 * 2/3 == 16 * 5/8 == 10. - * 32 * 2/3 = 21, 32 * 5/8 = 20. - * Its advantage is that it is faster to compute on machines with slow division. - * #define USABLE_FRACTION(n) (((n) >> 1) + ((n) >> 2) - ((n) >> 3)) - */ /* GROWTH_RATE. Growth rate upon hitting maximum load. * Currently set to used*3. @@ -536,7 +562,8 @@ _PyDict_CheckConsistency(PyObject *op, int check_content) } -static PyDictKeysObject *new_keys_object(Py_ssize_t size) +static PyDictKeysObject* +new_keys_object(Py_ssize_t size) { PyDictKeysObject *dk; Py_ssize_t es, usable; @@ -560,14 +587,17 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size) es = sizeof(Py_ssize_t); } -#if PyDict_MAXFREELIST > 0 - if (size == PyDict_MINSIZE && numfreekeys > 0) { - dk = keys_free_list[--numfreekeys]; + struct _Py_dict_state *state = get_dict_state(); +#ifdef Py_DEBUG + // new_keys_object() must not be called after _PyDict_Fini() + assert(state->keys_numfree != -1); +#endif + if (size == PyDict_MINSIZE && state->keys_numfree > 0) { + dk = state->keys_free_list[--state->keys_numfree]; } else -#endif { - dk = PyObject_MALLOC(sizeof(PyDictKeysObject) + dk = PyObject_Malloc(sizeof(PyDictKeysObject) + es * size + sizeof(PyDictKeyEntry) * usable); if (dk == NULL) { @@ -597,17 +627,20 @@ free_keys_object(PyDictKeysObject *keys) Py_XDECREF(entries[i].me_key); Py_XDECREF(entries[i].me_value); } -#if PyDict_MAXFREELIST > 0 - if (keys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) { - keys_free_list[numfreekeys++] = keys; + struct _Py_dict_state *state = get_dict_state(); +#ifdef Py_DEBUG + // free_keys_object() must not be called after _PyDict_Fini() + assert(state->keys_numfree != -1); +#endif + if (keys->dk_size == PyDict_MINSIZE && state->keys_numfree < PyDict_MAXFREELIST) { + state->keys_free_list[state->keys_numfree++] = keys; return; } -#endif - PyObject_FREE(keys); + PyObject_Free(keys); } #define new_values(size) PyMem_NEW(PyObject *, size) -#define free_values(values) PyMem_FREE(values) +#define free_values(values) PyMem_Free(values) /* Consumes a reference to the keys object */ static PyObject * @@ -615,16 +648,18 @@ new_dict(PyDictKeysObject *keys, PyObject **values) { PyDictObject *mp; assert(keys != NULL); -#if PyDict_MAXFREELIST > 0 - if (numfree) { - mp = free_list[--numfree]; + struct _Py_dict_state *state = get_dict_state(); +#ifdef Py_DEBUG + // new_dict() must not be called after _PyDict_Fini() + assert(state->numfree != -1); +#endif + if (state->numfree) { + mp = state->free_list[--state->numfree]; assert (mp != NULL); assert (Py_IS_TYPE(mp, &PyDict_Type)); _Py_NewReference((PyObject *)mp); } - else -#endif - { + else { mp = PyObject_GC_New(PyDictObject, &PyDict_Type); if (mp == NULL) { dictkeys_decref(keys); @@ -662,10 +697,11 @@ new_dict_with_shared_keys(PyDictKeysObject *keys) } -static PyObject * -clone_combined_dict(PyDictObject *orig) +static PyDictKeysObject * +clone_combined_dict_keys(PyDictObject *orig) { - assert(PyDict_CheckExact(orig)); + assert(PyDict_Check(orig)); + assert(Py_TYPE(orig)->tp_iter == (getiterfunc)dict_iter); assert(orig->ma_values == NULL); assert(orig->ma_keys->dk_refcnt == 1); @@ -692,19 +728,6 @@ clone_combined_dict(PyDictObject *orig) } } - PyDictObject *new = (PyDictObject *)new_dict(keys, NULL); - if (new == NULL) { - /* In case of an error, `new_dict()` takes care of - cleaning up `keys`. */ - return NULL; - } - new->ma_used = orig->ma_used; - ASSERT_CONSISTENT(new); - if (_PyObject_GC_IS_TRACKED(orig)) { - /* Maintain tracking. */ - _PyObject_GC_TRACK(new); - } - /* Since we copied the keys table we now have an extra reference in the system. Manually call increment _Py_RefTotal to signal that we have it now; calling dictkeys_incref would be an error as @@ -712,8 +735,7 @@ clone_combined_dict(PyDictObject *orig) #ifdef Py_REF_DEBUG _Py_RefTotal++; #endif - - return (PyObject *)new; + return keys; } PyObject * @@ -835,7 +857,6 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, unicodes is to override __eq__, and for speed we don't cater to that here. */ if (!PyUnicode_CheckExact(key)) { - mp->ma_keys->dk_lookup = lookdict; return lookdict(mp, key, hash, value_addr); } @@ -878,7 +899,6 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, unicodes is to override __eq__, and for speed we don't cater to that here. */ if (!PyUnicode_CheckExact(key)) { - mp->ma_keys->dk_lookup = lookdict; return lookdict(mp, key, hash, value_addr); } @@ -1037,7 +1057,7 @@ find_empty_slot(PyDictKeysObject *keys, Py_hash_t hash) static int insertion_resize(PyDictObject *mp) { - return dictresize(mp, GROWTH_RATE(mp)); + return dictresize(mp, calculate_keysize(GROWTH_RATE(mp))); } /* @@ -1062,7 +1082,6 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) if (ix == DKIX_ERROR) goto Fail; - assert(PyUnicode_CheckExact(key) || mp->ma_keys->dk_lookup == lookdict); MAINTAIN_TRACKING(mp, key, value); /* When insertion order is different from shared key, we can't share @@ -1084,6 +1103,9 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) if (insertion_resize(mp) < 0) goto Fail; } + if (!PyUnicode_CheckExact(key) && mp->ma_keys->dk_lookup != lookdict) { + mp->ma_keys->dk_lookup = lookdict; + } Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash); ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries]; dictkeys_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); @@ -1195,22 +1217,19 @@ After resizing a table is always combined, but can be resplit by make_keys_shared(). */ static int -dictresize(PyDictObject *mp, Py_ssize_t minsize) +dictresize(PyDictObject *mp, Py_ssize_t newsize) { - Py_ssize_t newsize, numentries; + Py_ssize_t numentries; PyDictKeysObject *oldkeys; PyObject **oldvalues; PyDictKeyEntry *oldentries, *newentries; - /* Find the smallest table size > minused. */ - for (newsize = PyDict_MINSIZE; - newsize < minsize && newsize > 0; - newsize <<= 1) - ; if (newsize <= 0) { PyErr_NoMemory(); return -1; } + assert(IS_POWER_OF_2(newsize)); + assert(newsize >= PyDict_MINSIZE); oldkeys = mp->ma_keys; @@ -1273,16 +1292,18 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize) #ifdef Py_REF_DEBUG _Py_RefTotal--; #endif -#if PyDict_MAXFREELIST > 0 + struct _Py_dict_state *state = get_dict_state(); +#ifdef Py_DEBUG + // dictresize() must not be called after _PyDict_Fini() + assert(state->keys_numfree != -1); +#endif if (oldkeys->dk_size == PyDict_MINSIZE && - numfreekeys < PyDict_MAXFREELIST) + state->keys_numfree < PyDict_MAXFREELIST) { - keys_free_list[numfreekeys++] = oldkeys; + state->keys_free_list[state->keys_numfree++] = oldkeys; } - else -#endif - { - PyObject_FREE(oldkeys); + else { + PyObject_Free(oldkeys); } } @@ -1354,13 +1375,8 @@ _PyDict_NewPresized(Py_ssize_t minused) newsize = max_presize; } else { - Py_ssize_t minsize = ESTIMATE_SIZE(minused); - newsize = PyDict_MINSIZE*2; - while (newsize < minsize) { - newsize <<= 1; - } + newsize = estimate_keysize(minused); } - assert(IS_POWER_OF_2(newsize)); new_keys = new_keys_object(newsize); if (new_keys == NULL) @@ -1381,14 +1397,12 @@ _PyDict_NewPresized(Py_ssize_t minused) PyObject * PyDict_GetItem(PyObject *op, PyObject *key) { - Py_hash_t hash; - Py_ssize_t ix; + if (!PyDict_Check(op)) { + return NULL; + } PyDictObject *mp = (PyDictObject *)op; - PyThreadState *tstate; - PyObject *value; - if (!PyDict_Check(op)) - return NULL; + Py_hash_t hash; if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { @@ -1399,30 +1413,66 @@ PyDict_GetItem(PyObject *op, PyObject *key) } } - /* We can arrive here with a NULL tstate during initialization: try - running "python -Wi" for an example related to string interning. - Let's just hope that no exception occurs then... This must be - _PyThreadState_GET() and not PyThreadState_Get() because the latter - abort Python if tstate is NULL. */ - tstate = _PyThreadState_GET(); - if (tstate != NULL && tstate->curexc_type != NULL) { - /* preserve the existing exception */ - PyObject *err_type, *err_value, *err_tb; - PyErr_Fetch(&err_type, &err_value, &err_tb); - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value); - /* ignore errors */ - PyErr_Restore(err_type, err_value, err_tb); - if (ix < 0) - return NULL; + PyThreadState *tstate = _PyThreadState_GET(); +#ifdef Py_DEBUG + // bpo-40839: Before Python 3.10, it was possible to call PyDict_GetItem() + // with the GIL released. + _Py_EnsureTstateNotNULL(tstate); +#endif + + /* Preserve the existing exception */ + PyObject *exc_type, *exc_value, *exc_tb; + PyObject *value; + Py_ssize_t ix; + + _PyErr_Fetch(tstate, &exc_type, &exc_value, &exc_tb); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value); + + /* Ignore any exception raised by the lookup */ + _PyErr_Restore(tstate, exc_type, exc_value, exc_tb); + + if (ix < 0) { + return NULL; } - else { - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value); - if (ix < 0) { - PyErr_Clear(); - return NULL; + return value; +} + +Py_ssize_t +_PyDict_GetItemHint(PyDictObject *mp, PyObject *key, + Py_ssize_t hint, PyObject **value) +{ + assert(*value == NULL); + assert(PyDict_CheckExact((PyObject*)mp)); + assert(PyUnicode_CheckExact(key)); + + if (hint >= 0 && hint < mp->ma_keys->dk_nentries) { + PyObject *res = NULL; + + PyDictKeyEntry *ep = DK_ENTRIES(mp->ma_keys) + (size_t)hint; + if (ep->me_key == key) { + if (mp->ma_keys->dk_lookup == lookdict_split) { + assert(mp->ma_values != NULL); + res = mp->ma_values[(size_t)hint]; + } + else { + res = ep->me_value; + } + if (res != NULL) { + *value = res; + return hint; + } } } - return value; + + Py_hash_t hash = ((PyASCIIObject *) key)->hash; + if (hash == -1) { + hash = PyObject_Hash(key); + if (hash == -1) { + return -1; + } + } + + return (mp->ma_keys->dk_lookup)(mp, key, hash, value); } /* Same as PyDict_GetItemWithError() but with hash supplied by caller. @@ -1933,7 +1983,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) PyObject *key; Py_hash_t hash; - if (dictresize(mp, ESTIMATE_SIZE(PyDict_GET_SIZE(iterable)))) { + if (dictresize(mp, estimate_keysize(PyDict_GET_SIZE(iterable)))) { Py_DECREF(d); return NULL; } @@ -1952,7 +2002,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) PyObject *key; Py_hash_t hash; - if (dictresize(mp, ESTIMATE_SIZE(PySet_GET_SIZE(iterable)))) { + if (dictresize(mp, estimate_keysize(PySet_GET_SIZE(iterable)))) { Py_DECREF(d); return NULL; } @@ -2025,13 +2075,15 @@ dict_dealloc(PyDictObject *mp) assert(keys->dk_refcnt == 1); dictkeys_decref(keys); } -#if PyDict_MAXFREELIST > 0 - if (numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) { - free_list[numfree++] = mp; - } - else + struct _Py_dict_state *state = get_dict_state(); +#ifdef Py_DEBUG + // new_dict() must not be called after _PyDict_Fini() + assert(state->numfree != -1); #endif - { + if (state->numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) { + state->free_list[state->numfree++] = mp; + } + else { Py_TYPE(mp)->tp_free((PyObject *)mp); } Py_TRASHCAN_END @@ -2465,8 +2517,8 @@ PyDict_MergeFromSeq2(PyObject *d, PyObject *seq2, int override) goto Fail; } } - else if (PyDict_GetItemWithError(d, key) == NULL) { - if (PyErr_Occurred() || PyDict_SetItem(d, key, value) < 0) { + else { + if (PyDict_SetDefault(d, key, value) == NULL) { Py_DECREF(key); Py_DECREF(value); goto Fail; @@ -2515,18 +2567,51 @@ dict_merge(PyObject *a, PyObject *b, int override) if (other == mp || other->ma_used == 0) /* a.update(a) or a.update({}); nothing to do */ return 0; - if (mp->ma_used == 0) + if (mp->ma_used == 0) { /* Since the target dict is empty, PyDict_GetItem() * always returns NULL. Setting override to 1 * skips the unnecessary test. */ override = 1; + PyDictKeysObject *okeys = other->ma_keys; + + // If other is clean, combined, and just allocated, just clone it. + if (other->ma_values == NULL && + other->ma_used == okeys->dk_nentries && + (okeys->dk_size == PyDict_MINSIZE || + USABLE_FRACTION(okeys->dk_size/2) < other->ma_used)) { + PyDictKeysObject *keys = clone_combined_dict_keys(other); + if (keys == NULL) { + return -1; + } + + dictkeys_decref(mp->ma_keys); + mp->ma_keys = keys; + if (mp->ma_values != NULL) { + if (mp->ma_values != empty_values) { + free_values(mp->ma_values); + } + mp->ma_values = NULL; + } + + mp->ma_used = other->ma_used; + mp->ma_version_tag = DICT_NEXT_VERSION(); + ASSERT_CONSISTENT(mp); + + if (_PyObject_GC_IS_TRACKED(other) && !_PyObject_GC_IS_TRACKED(mp)) { + /* Maintain tracking. */ + _PyObject_GC_TRACK(mp); + } + + return 0; + } + } /* Do one big resize at the start, rather than * incrementally resizing as we insert new items. Expect * that there will be no (or few) overlapping keys. */ if (USABLE_FRACTION(mp->ma_keys->dk_size) < other->ma_used) { - if (dictresize(mp, ESTIMATE_SIZE(mp->ma_used + other->ma_used))) { + if (dictresize(mp, estimate_keysize(mp->ma_used + other->ma_used))) { return -1; } } @@ -2548,19 +2633,20 @@ dict_merge(PyObject *a, PyObject *b, int override) Py_INCREF(value); if (override == 1) err = insertdict(mp, key, hash, value); - else if (_PyDict_GetItem_KnownHash(a, key, hash) == NULL) { - if (PyErr_Occurred()) { - Py_DECREF(value); - Py_DECREF(key); - return -1; + else { + err = _PyDict_Contains_KnownHash(a, key, hash); + if (err == 0) { + err = insertdict(mp, key, hash, value); + } + else if (err > 0) { + if (override != 0) { + _PyErr_SetKeyError(key); + Py_DECREF(value); + Py_DECREF(key); + return -1; + } + err = 0; } - err = insertdict(mp, key, hash, value); - } - else if (override != 0) { - _PyErr_SetKeyError(key); - Py_DECREF(value); - Py_DECREF(key); - return -1; } Py_DECREF(value); Py_DECREF(key); @@ -2597,18 +2683,16 @@ dict_merge(PyObject *a, PyObject *b, int override) for (key = PyIter_Next(iter); key; key = PyIter_Next(iter)) { if (override != 1) { - if (PyDict_GetItemWithError(a, key) != NULL) { - if (override != 0) { + status = PyDict_Contains(a, key); + if (status != 0) { + if (status > 0) { + if (override == 0) { + Py_DECREF(key); + continue; + } _PyErr_SetKeyError(key); - Py_DECREF(key); - Py_DECREF(iter); - return -1; } Py_DECREF(key); - continue; - } - else if (PyErr_Occurred()) { - Py_DECREF(key); Py_DECREF(iter); return -1; } @@ -2706,12 +2790,13 @@ PyDict_Copy(PyObject *o) return (PyObject *)split_copy; } - if (PyDict_CheckExact(mp) && mp->ma_values == NULL && + if (Py_TYPE(mp)->tp_iter == (getiterfunc)dict_iter && + mp->ma_values == NULL && (mp->ma_used >= (mp->ma_keys->dk_nentries * 2) / 3)) { /* Use fast-copy if: - (1) 'mp' is an instance of a subclassed dict; and + (1) type(mp) doesn't override tp_iter; and (2) 'mp' is not a split-dict; and @@ -2723,13 +2808,31 @@ PyDict_Copy(PyObject *o) operations and copied after that. In cases like this, we defer to PyDict_Merge, which produces a compacted copy. */ - return clone_combined_dict(mp); + PyDictKeysObject *keys = clone_combined_dict_keys(mp); + if (keys == NULL) { + return NULL; + } + PyDictObject *new = (PyDictObject *)new_dict(keys, NULL); + if (new == NULL) { + /* In case of an error, `new_dict()` takes care of + cleaning up `keys`. */ + return NULL; + } + + new->ma_used = mp->ma_used; + ASSERT_CONSISTENT(new); + if (_PyObject_GC_IS_TRACKED(mp)) { + /* Maintain tracking. */ + _PyObject_GC_TRACK(new); + } + + return (PyObject *)new; } copy = PyDict_New(); if (copy == NULL) return NULL; - if (PyDict_Merge(copy, o, 1) == 0) + if (dict_merge(copy, o, 1) == 0) return copy; Py_DECREF(copy); return NULL; @@ -2965,6 +3068,9 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) return NULL; } } + if (!PyUnicode_CheckExact(key) && mp->ma_keys->dk_lookup != lookdict) { + mp->ma_keys->dk_lookup = lookdict; + } Py_ssize_t hashpos = find_empty_slot(mp->ma_keys, hash); ep0 = DK_ENTRIES(mp->ma_keys); ep = &ep0[mp->ma_keys->dk_nentries]; @@ -3042,12 +3148,13 @@ dict.pop D.pop(k[,d]) -> v, remove specified key and return the corresponding value. -If key is not found, default is returned if given, otherwise KeyError is raised +If the key is not found, return the default if given; otherwise, +raise a KeyError. [clinic start generated code]*/ static PyObject * dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value) -/*[clinic end generated code: output=3abb47b89f24c21c input=eeebec7812190348]*/ +/*[clinic end generated code: output=3abb47b89f24c21c input=e221baa01044c44c]*/ { return _PyDict_Pop((PyObject*)self, key, default_value); } @@ -3302,7 +3409,7 @@ PyDict_Contains(PyObject *op, PyObject *key) /* Internal version of PyDict_Contains used when the hash value is already known */ int -_PyDict_Contains(PyObject *op, PyObject *key, Py_hash_t hash) +_PyDict_Contains_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) { PyDictObject *mp = (PyDictObject *)op; PyObject *value; @@ -3314,6 +3421,16 @@ _PyDict_Contains(PyObject *op, PyObject *key, Py_hash_t hash) return (ix != DKIX_EMPTY && value != NULL); } +int +_PyDict_ContainsId(PyObject *op, struct _Py_Identifier *key) +{ + PyObject *kv = _PyUnicode_FromId(key); /* borrowed */ + if (kv == NULL) { + return -1; + } + return PyDict_Contains(op, kv); +} + /* Hack to implement "key in dict" */ static PySequenceMethods dict_as_sequence = { 0, /* sq_length */ @@ -3346,16 +3463,15 @@ dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds) d = (PyDictObject *)self; /* The object has been implicitly tracked by tp_alloc */ - if (type == &PyDict_Type) + if (type == &PyDict_Type) { _PyObject_GC_UNTRACK(d); + } d->ma_used = 0; d->ma_version_tag = DICT_NEXT_VERSION(); - d->ma_keys = new_keys_object(PyDict_MINSIZE); - if (d->ma_keys == NULL) { - Py_DECREF(self); - return NULL; - } + dictkeys_incref(Py_EMPTY_KEYS); + d->ma_keys = Py_EMPTY_KEYS; + d->ma_values = empty_values; ASSERT_CONSISTENT(d); return self; } @@ -3436,7 +3552,8 @@ PyTypeObject PyDict_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_DICT_SUBCLASS | + _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_MAPPING, /* tp_flags */ dictionary_doc, /* tp_doc */ dict_traverse, /* tp_traverse */ dict_tp_clear, /* tp_clear */ @@ -3459,18 +3576,6 @@ PyTypeObject PyDict_Type = { .tp_vectorcall = dict_vectorcall, }; -PyObject * -_PyDict_GetItemId(PyObject *dp, struct _Py_Identifier *key) -{ - PyObject *kv; - kv = _PyUnicode_FromId(key); /* borrowed */ - if (kv == NULL) { - PyErr_Clear(); - return NULL; - } - return PyDict_GetItem(dp, kv); -} - /* For backward compatibility with old dictionary interface */ PyObject * @@ -4129,6 +4234,22 @@ _PyDictView_New(PyObject *dict, PyTypeObject *type) return (PyObject *)dv; } +static PyObject * +dictview_mapping(PyObject *view, void *Py_UNUSED(ignored)) { + assert(view != NULL); + assert(PyDictKeys_Check(view) + || PyDictValues_Check(view) + || PyDictItems_Check(view)); + PyObject *mapping = (PyObject *)((_PyDictViewObject *)view)->dv_dict; + return PyDictProxy_New(mapping); +} + +static PyGetSetDef dictview_getset[] = { + {"mapping", dictview_mapping, (setter)NULL, + "dictionary that this view refers to", NULL}, + {0} +}; + /* TODO(guido): The views objects are not complete: * support more set operations @@ -4338,7 +4459,7 @@ _PyDictView_Intersect(PyObject* self, PyObject *other) /* if other is a set and self is smaller than other, reuse set intersection logic */ - if (Py_IS_TYPE(other, &PySet_Type) && len_self <= PyObject_Size(other)) { + if (PySet_CheckExact(other) && len_self <= PyObject_Size(other)) { _Py_IDENTIFIER(intersection); return _PyObject_CallMethodIdObjArgs(other, &PyId_intersection, self, NULL); } @@ -4416,9 +4537,99 @@ dictviews_or(PyObject* self, PyObject *other) return result; } +static PyObject * +dictitems_xor(PyObject *self, PyObject *other) +{ + assert(PyDictItems_Check(self)); + assert(PyDictItems_Check(other)); + PyObject *d1 = (PyObject *)((_PyDictViewObject *)self)->dv_dict; + PyObject *d2 = (PyObject *)((_PyDictViewObject *)other)->dv_dict; + + PyObject *temp_dict = PyDict_Copy(d1); + if (temp_dict == NULL) { + return NULL; + } + PyObject *result_set = PySet_New(NULL); + if (result_set == NULL) { + Py_CLEAR(temp_dict); + return NULL; + } + + PyObject *key = NULL, *val1 = NULL, *val2 = NULL; + Py_ssize_t pos = 0; + Py_hash_t hash; + + while (_PyDict_Next(d2, &pos, &key, &val2, &hash)) { + Py_INCREF(key); + Py_INCREF(val2); + val1 = _PyDict_GetItem_KnownHash(temp_dict, key, hash); + + int to_delete; + if (val1 == NULL) { + if (PyErr_Occurred()) { + goto error; + } + to_delete = 0; + } + else { + Py_INCREF(val1); + to_delete = PyObject_RichCompareBool(val1, val2, Py_EQ); + if (to_delete < 0) { + goto error; + } + } + + if (to_delete) { + if (_PyDict_DelItem_KnownHash(temp_dict, key, hash) < 0) { + goto error; + } + } + else { + PyObject *pair = PyTuple_Pack(2, key, val2); + if (pair == NULL) { + goto error; + } + if (PySet_Add(result_set, pair) < 0) { + Py_DECREF(pair); + goto error; + } + Py_DECREF(pair); + } + Py_DECREF(key); + Py_XDECREF(val1); + Py_DECREF(val2); + } + key = val1 = val2 = NULL; + + _Py_IDENTIFIER(items); + PyObject *remaining_pairs = _PyObject_CallMethodIdNoArgs(temp_dict, + &PyId_items); + if (remaining_pairs == NULL) { + goto error; + } + if (_PySet_Update(result_set, remaining_pairs) < 0) { + Py_DECREF(remaining_pairs); + goto error; + } + Py_DECREF(temp_dict); + Py_DECREF(remaining_pairs); + return result_set; + +error: + Py_XDECREF(temp_dict); + Py_XDECREF(result_set); + Py_XDECREF(key); + Py_XDECREF(val1); + Py_XDECREF(val2); + return NULL; +} + static PyObject* dictviews_xor(PyObject* self, PyObject *other) { + if (PyDictItems_Check(self) && PyDictItems_Check(other)) { + return dictitems_xor(self, other); + } PyObject *result = dictviews_to_set(self); if (result == NULL) { return NULL; @@ -4552,7 +4763,7 @@ PyTypeObject PyDictKeys_Type = { (getiterfunc)dictkeys_iter, /* tp_iter */ 0, /* tp_iternext */ dictkeys_methods, /* tp_methods */ - 0, + .tp_getset = dictview_getset, }; static PyObject * @@ -4658,7 +4869,7 @@ PyTypeObject PyDictItems_Type = { (getiterfunc)dictitems_iter, /* tp_iter */ 0, /* tp_iternext */ dictitems_methods, /* tp_methods */ - 0, + .tp_getset = dictview_getset, }; static PyObject * @@ -4739,7 +4950,7 @@ PyTypeObject PyDictValues_Type = { (getiterfunc)dictvalues_iter, /* tp_iter */ 0, /* tp_iternext */ dictvalues_methods, /* tp_methods */ - 0, + .tp_getset = dictview_getset, }; static PyObject * @@ -4764,10 +4975,12 @@ PyDictKeysObject * _PyDict_NewKeysForClass(void) { PyDictKeysObject *keys = new_keys_object(PyDict_MINSIZE); - if (keys == NULL) + if (keys == NULL) { PyErr_Clear(); - else + } + else { keys->dk_lookup = lookdict_split; + } return keys; } diff --git a/contrib/tools/python3/src/Objects/enumobject.c b/contrib/tools/python3/src/Objects/enumobject.c index bdd0ea5f39..98ece3f13f 100644 --- a/contrib/tools/python3/src/Objects/enumobject.c +++ b/contrib/tools/python3/src/Objects/enumobject.c @@ -1,6 +1,7 @@ /* enumerate object */ #include "Python.h" +#include "pycore_long.h" // _PyLong_GetOne() #include "pycore_object.h" // _PyObject_GC_TRACK() #include "clinic/enumobject.c.h" @@ -116,7 +117,7 @@ enum_next_long(enumobject *en, PyObject* next_item) } next_index = en->en_longindex; assert(next_index != NULL); - stepped_up = PyNumber_Add(next_index, _PyLong_One); + stepped_up = PyNumber_Add(next_index, _PyLong_GetOne()); if (stepped_up == NULL) { Py_DECREF(next_item); return NULL; @@ -325,6 +326,24 @@ reversed_new_impl(PyTypeObject *type, PyObject *seq) return (PyObject *)ro; } +static PyObject * +reversed_vectorcall(PyObject *type, PyObject * const*args, + size_t nargsf, PyObject *kwnames) +{ + assert(PyType_Check(type)); + + if (!_PyArg_NoKwnames("reversed", kwnames)) { + return NULL; + } + + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + if (!_PyArg_CheckPositional("reversed", nargs, 1, 1)) { + return NULL; + } + + return reversed_new_impl((PyTypeObject *)type, args[0]); +} + static void reversed_dealloc(reversedobject *ro) { @@ -456,4 +475,5 @@ PyTypeObject PyReversed_Type = { PyType_GenericAlloc, /* tp_alloc */ reversed_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ + .tp_vectorcall = (vectorcallfunc)reversed_vectorcall, }; diff --git a/contrib/tools/python3/src/Objects/exceptions.c b/contrib/tools/python3/src/Objects/exceptions.c index e67ecfab85..6537a7ccd1 100644 --- a/contrib/tools/python3/src/Objects/exceptions.c +++ b/contrib/tools/python3/src/Objects/exceptions.c @@ -19,8 +19,13 @@ PyObject *PyExc_IOError = NULL; PyObject *PyExc_WindowsError = NULL; #endif -/* The dict map from errno codes to OSError subclasses */ -static PyObject *errnomap = NULL; + +static struct _Py_exc_state* +get_exc_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->exc_state; +} /* NOTE: If the exception class hierarchy changes, don't forget to update @@ -359,8 +364,6 @@ PyException_SetContext(PyObject *self, PyObject *context) Py_XSETREF(_PyBaseExceptionObject_cast(self)->context, context); } -#undef PyExceptionClass_Name - const char * PyExceptionClass_Name(PyObject *ob) { @@ -985,10 +988,11 @@ OSError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) )) goto error; + struct _Py_exc_state *state = get_exc_state(); if (myerrno && PyLong_Check(myerrno) && - errnomap && (PyObject *) type == PyExc_OSError) { + state->errnomap && (PyObject *) type == PyExc_OSError) { PyObject *newtype; - newtype = PyDict_GetItemWithError(errnomap, myerrno); + newtype = PyDict_GetItemWithError(state->errnomap, myerrno); if (newtype) { assert(PyType_Check(newtype)); type = (PyTypeObject *) newtype; @@ -1322,29 +1326,155 @@ SimpleExtendsException(PyExc_RuntimeError, NotImplementedError, /* * NameError extends Exception */ -SimpleExtendsException(PyExc_Exception, NameError, - "Name not found globally."); + +static int +NameError_init(PyNameErrorObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"name", NULL}; + PyObject *name = NULL; + + if (BaseException_init((PyBaseExceptionObject *)self, args, NULL) == -1) { + return -1; + } + + PyObject *empty_tuple = PyTuple_New(0); + if (!empty_tuple) { + return -1; + } + if (!PyArg_ParseTupleAndKeywords(empty_tuple, kwds, "|$O:NameError", kwlist, + &name)) { + Py_DECREF(empty_tuple); + return -1; + } + Py_DECREF(empty_tuple); + + Py_XINCREF(name); + Py_XSETREF(self->name, name); + + return 0; +} + +static int +NameError_clear(PyNameErrorObject *self) +{ + Py_CLEAR(self->name); + return BaseException_clear((PyBaseExceptionObject *)self); +} + +static void +NameError_dealloc(PyNameErrorObject *self) +{ + _PyObject_GC_UNTRACK(self); + NameError_clear(self); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static int +NameError_traverse(PyNameErrorObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->name); + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); +} + +static PyMemberDef NameError_members[] = { + {"name", T_OBJECT, offsetof(PyNameErrorObject, name), 0, PyDoc_STR("name")}, + {NULL} /* Sentinel */ +}; + +static PyMethodDef NameError_methods[] = { + {NULL} /* Sentinel */ +}; + +ComplexExtendsException(PyExc_Exception, NameError, + NameError, 0, + NameError_methods, NameError_members, + 0, BaseException_str, "Name not found globally."); /* * UnboundLocalError extends NameError */ -SimpleExtendsException(PyExc_NameError, UnboundLocalError, + +MiddlingExtendsException(PyExc_NameError, UnboundLocalError, NameError, "Local name referenced but not bound to a value."); /* * AttributeError extends Exception */ -SimpleExtendsException(PyExc_Exception, AttributeError, - "Attribute not found."); +static int +AttributeError_init(PyAttributeErrorObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"name", "obj", NULL}; + PyObject *name = NULL; + PyObject *obj = NULL; + + if (BaseException_init((PyBaseExceptionObject *)self, args, NULL) == -1) { + return -1; + } + + PyObject *empty_tuple = PyTuple_New(0); + if (!empty_tuple) { + return -1; + } + if (!PyArg_ParseTupleAndKeywords(empty_tuple, kwds, "|$OO:AttributeError", kwlist, + &name, &obj)) { + Py_DECREF(empty_tuple); + return -1; + } + Py_DECREF(empty_tuple); + + Py_XINCREF(name); + Py_XSETREF(self->name, name); + + Py_XINCREF(obj); + Py_XSETREF(self->obj, obj); + + return 0; +} + +static int +AttributeError_clear(PyAttributeErrorObject *self) +{ + Py_CLEAR(self->obj); + Py_CLEAR(self->name); + return BaseException_clear((PyBaseExceptionObject *)self); +} + +static void +AttributeError_dealloc(PyAttributeErrorObject *self) +{ + _PyObject_GC_UNTRACK(self); + AttributeError_clear(self); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static int +AttributeError_traverse(PyAttributeErrorObject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->obj); + Py_VISIT(self->name); + return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); +} + +static PyMemberDef AttributeError_members[] = { + {"name", T_OBJECT, offsetof(PyAttributeErrorObject, name), 0, PyDoc_STR("attribute name")}, + {"obj", T_OBJECT, offsetof(PyAttributeErrorObject, obj), 0, PyDoc_STR("object")}, + {NULL} /* Sentinel */ +}; + +static PyMethodDef AttributeError_methods[] = { + {NULL} /* Sentinel */ +}; + +ComplexExtendsException(PyExc_Exception, AttributeError, + AttributeError, 0, + AttributeError_methods, AttributeError_members, + 0, BaseException_str, "Attribute not found."); /* * SyntaxError extends Exception */ -/* Helper function to customize error message for some syntax errors */ -static int _report_missing_parentheses(PySyntaxErrorObject *self); - static int SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) { @@ -1361,39 +1491,30 @@ SyntaxError_init(PySyntaxErrorObject *self, PyObject *args, PyObject *kwds) if (lenargs == 2) { info = PyTuple_GET_ITEM(args, 1); info = PySequence_Tuple(info); - if (!info) + if (!info) { return -1; + } - if (PyTuple_GET_SIZE(info) != 4) { - /* not a very good error message, but it's what Python 2.4 gives */ - PyErr_SetString(PyExc_IndexError, "tuple index out of range"); + self->end_lineno = NULL; + self->end_offset = NULL; + if (!PyArg_ParseTuple(info, "OOOO|OO", + &self->filename, &self->lineno, + &self->offset, &self->text, + &self->end_lineno, &self->end_offset)) { Py_DECREF(info); return -1; } - Py_INCREF(PyTuple_GET_ITEM(info, 0)); - Py_XSETREF(self->filename, PyTuple_GET_ITEM(info, 0)); - - Py_INCREF(PyTuple_GET_ITEM(info, 1)); - Py_XSETREF(self->lineno, PyTuple_GET_ITEM(info, 1)); - - Py_INCREF(PyTuple_GET_ITEM(info, 2)); - Py_XSETREF(self->offset, PyTuple_GET_ITEM(info, 2)); - - Py_INCREF(PyTuple_GET_ITEM(info, 3)); - Py_XSETREF(self->text, PyTuple_GET_ITEM(info, 3)); - + Py_INCREF(self->filename); + Py_INCREF(self->lineno); + Py_INCREF(self->offset); + Py_INCREF(self->text); + Py_XINCREF(self->end_lineno); + Py_XINCREF(self->end_offset); Py_DECREF(info); - /* - * Issue #21669: Custom error for 'print' & 'exec' as statements - * - * Only applies to SyntaxError instances, not to subclasses such - * as TabError or IndentationError (see issue #31161) - */ - if (Py_IS_TYPE(self, (PyTypeObject *)PyExc_SyntaxError) && - self->text && PyUnicode_Check(self->text) && - _report_missing_parentheses(self) < 0) { + if (self->end_lineno != NULL && self->end_offset == NULL) { + PyErr_SetString(PyExc_TypeError, "end_offset must be provided when end_lineno is provided"); return -1; } } @@ -1407,6 +1528,8 @@ SyntaxError_clear(PySyntaxErrorObject *self) Py_CLEAR(self->filename); Py_CLEAR(self->lineno); Py_CLEAR(self->offset); + Py_CLEAR(self->end_lineno); + Py_CLEAR(self->end_offset); Py_CLEAR(self->text); Py_CLEAR(self->print_file_and_line); return BaseException_clear((PyBaseExceptionObject *)self); @@ -1427,6 +1550,8 @@ SyntaxError_traverse(PySyntaxErrorObject *self, visitproc visit, void *arg) Py_VISIT(self->filename); Py_VISIT(self->lineno); Py_VISIT(self->offset); + Py_VISIT(self->end_lineno); + Py_VISIT(self->end_offset); Py_VISIT(self->text); Py_VISIT(self->print_file_and_line); return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg); @@ -1517,6 +1642,10 @@ static PyMemberDef SyntaxError_members[] = { PyDoc_STR("exception offset")}, {"text", T_OBJECT, offsetof(PySyntaxErrorObject, text), 0, PyDoc_STR("exception text")}, + {"end_lineno", T_OBJECT, offsetof(PySyntaxErrorObject, end_lineno), 0, + PyDoc_STR("exception end lineno")}, + {"end_offset", T_OBJECT, offsetof(PySyntaxErrorObject, end_offset), 0, + PyDoc_STR("exception end offset")}, {"print_file_and_line", T_OBJECT, offsetof(PySyntaxErrorObject, print_file_and_line), 0, PyDoc_STR("exception print_file_and_line")}, @@ -2274,8 +2403,6 @@ SimpleExtendsException(PyExc_Exception, ReferenceError, */ #define MEMERRORS_SAVE 16 -static PyBaseExceptionObject *memerrors_freelist = NULL; -static int memerrors_numfree = 0; static PyObject * MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) @@ -2288,16 +2415,21 @@ MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return BaseException_new(type, args, kwds); } - if (memerrors_freelist == NULL) + struct _Py_exc_state *state = get_exc_state(); + if (state->memerrors_freelist == NULL) { return BaseException_new(type, args, kwds); + } + /* Fetch object from freelist and revive it */ - self = memerrors_freelist; + self = state->memerrors_freelist; self->args = PyTuple_New(0); /* This shouldn't happen since the empty tuple is persistent */ - if (self->args == NULL) + if (self->args == NULL) { return NULL; - memerrors_freelist = (PyBaseExceptionObject *) self->dict; - memerrors_numfree--; + } + + state->memerrors_freelist = (PyBaseExceptionObject *) self->dict; + state->memerrors_numfree--; self->dict = NULL; _Py_NewReference((PyObject *)self); _PyObject_GC_TRACK(self); @@ -2309,6 +2441,8 @@ MemoryError_dealloc(PyBaseExceptionObject *self) { BaseException_clear(self); + /* If this is a subclass of MemoryError, we don't need to + * do anything in the free-list*/ if (!Py_IS_TYPE(self, (PyTypeObject *) PyExc_MemoryError)) { Py_TYPE(self)->tp_free((PyObject *)self); return; @@ -2316,12 +2450,14 @@ MemoryError_dealloc(PyBaseExceptionObject *self) _PyObject_GC_UNTRACK(self); - if (memerrors_numfree >= MEMERRORS_SAVE) + struct _Py_exc_state *state = get_exc_state(); + if (state->memerrors_numfree >= MEMERRORS_SAVE) { Py_TYPE(self)->tp_free((PyObject *)self); + } else { - self->dict = (PyObject *) memerrors_freelist; - memerrors_freelist = self; - memerrors_numfree++; + self->dict = (PyObject *) state->memerrors_freelist; + state->memerrors_freelist = self; + state->memerrors_numfree++; } } @@ -2346,11 +2482,11 @@ preallocate_memerrors(void) } static void -free_preallocated_memerrors(void) +free_preallocated_memerrors(struct _Py_exc_state *state) { - while (memerrors_freelist != NULL) { - PyObject *self = (PyObject *) memerrors_freelist; - memerrors_freelist = (PyBaseExceptionObject *) memerrors_freelist->dict; + while (state->memerrors_freelist != NULL) { + PyObject *self = (PyObject *) state->memerrors_freelist; + state->memerrors_freelist = (PyBaseExceptionObject *)state->memerrors_freelist->dict; Py_TYPE(self)->tp_free((PyObject *)self); } } @@ -2454,6 +2590,13 @@ SimpleExtendsException(PyExc_Warning, BytesWarning, /* + * EncodingWarning extends Warning + */ +SimpleExtendsException(PyExc_Warning, EncodingWarning, + "Base class for warnings about encodings."); + + +/* * ResourceWarning extends Warning */ SimpleExtendsException(PyExc_Warning, ResourceWarning, @@ -2518,8 +2661,10 @@ SimpleExtendsException(PyExc_Warning, ResourceWarning, #endif /* MS_WINDOWS */ PyStatus -_PyExc_Init(void) +_PyExc_Init(PyInterpreterState *interp) { + struct _Py_exc_state *state = &interp->exc_state; + #define PRE_INIT(TYPE) \ if (!(_PyExc_ ## TYPE.tp_flags & Py_TPFLAGS_READY)) { \ if (PyType_Ready(&_PyExc_ ## TYPE) < 0) { \ @@ -2532,7 +2677,7 @@ _PyExc_Init(void) do { \ PyObject *_code = PyLong_FromLong(CODE); \ assert(_PyObject_RealIsSubclass(PyExc_ ## TYPE, PyExc_OSError)); \ - if (!_code || PyDict_SetItem(errnomap, _code, PyExc_ ## TYPE)) { \ + if (!_code || PyDict_SetItem(state->errnomap, _code, PyExc_ ## TYPE)) { \ Py_XDECREF(_code); \ return _PyStatus_ERR("errmap insertion problem."); \ } \ @@ -2579,6 +2724,7 @@ _PyExc_Init(void) PRE_INIT(BufferError); PRE_INIT(Warning); PRE_INIT(UserWarning); + PRE_INIT(EncodingWarning); PRE_INIT(DeprecationWarning); PRE_INIT(PendingDeprecationWarning); PRE_INIT(SyntaxWarning); @@ -2608,15 +2754,14 @@ _PyExc_Init(void) PRE_INIT(TimeoutError); if (preallocate_memerrors() < 0) { - return _PyStatus_ERR("Could not preallocate MemoryError object"); + return _PyStatus_NO_MEMORY(); } /* Add exceptions to errnomap */ - if (!errnomap) { - errnomap = PyDict_New(); - if (!errnomap) { - return _PyStatus_ERR("Cannot allocate map from errnos to OSError subclasses"); - } + assert(state->errnomap == NULL); + state->errnomap = PyDict_New(); + if (!state->errnomap) { + return _PyStatus_NO_MEMORY(); } ADD_ERRNO(BlockingIOError, EAGAIN); @@ -2719,6 +2864,7 @@ _PyBuiltins_AddExceptions(PyObject *bltinmod) POST_INIT(BufferError); POST_INIT(Warning); POST_INIT(UserWarning); + POST_INIT(EncodingWarning); POST_INIT(DeprecationWarning); POST_INIT(PendingDeprecationWarning); POST_INIT(SyntaxWarning); @@ -2754,10 +2900,11 @@ _PyBuiltins_AddExceptions(PyObject *bltinmod) } void -_PyExc_Fini(void) +_PyExc_Fini(PyInterpreterState *interp) { - free_preallocated_memerrors(); - Py_CLEAR(errnomap); + struct _Py_exc_state *state = &interp->exc_state; + free_preallocated_memerrors(state); + Py_CLEAR(state->errnomap); } /* Helper to do the equivalent of "raise X from Y" in C, but always using @@ -2890,189 +3037,3 @@ _PyErr_TrySetFromCause(const char *format, ...) PyErr_Restore(new_exc, new_val, new_tb); return new_val; } - - -/* To help with migration from Python 2, SyntaxError.__init__ applies some - * heuristics to try to report a more meaningful exception when print and - * exec are used like statements. - * - * The heuristics are currently expected to detect the following cases: - * - top level statement - * - statement in a nested suite - * - trailing section of a one line complex statement - * - * They're currently known not to trigger: - * - after a semi-colon - * - * The error message can be a bit odd in cases where the "arguments" are - * completely illegal syntactically, but that isn't worth the hassle of - * fixing. - * - * We also can't do anything about cases that are legal Python 3 syntax - * but mean something entirely different from what they did in Python 2 - * (omitting the arguments entirely, printing items preceded by a unary plus - * or minus, using the stream redirection syntax). - */ - - -// Static helper for setting legacy print error message -static int -_set_legacy_print_statement_msg(PySyntaxErrorObject *self, Py_ssize_t start) -{ - // PRINT_OFFSET is to remove the `print ` prefix from the data. - const int PRINT_OFFSET = 6; - const int STRIP_BOTH = 2; - Py_ssize_t start_pos = start + PRINT_OFFSET; - Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text); - Py_UCS4 semicolon = ';'; - Py_ssize_t end_pos = PyUnicode_FindChar(self->text, semicolon, - start_pos, text_len, 1); - if (end_pos < -1) { - return -1; - } else if (end_pos == -1) { - end_pos = text_len; - } - - PyObject *data = PyUnicode_Substring(self->text, start_pos, end_pos); - if (data == NULL) { - return -1; - } - - PyObject *strip_sep_obj = PyUnicode_FromString(" \t\r\n"); - if (strip_sep_obj == NULL) { - Py_DECREF(data); - return -1; - } - - PyObject *new_data = _PyUnicode_XStrip(data, STRIP_BOTH, strip_sep_obj); - Py_DECREF(data); - Py_DECREF(strip_sep_obj); - if (new_data == NULL) { - return -1; - } - // gets the modified text_len after stripping `print ` - text_len = PyUnicode_GET_LENGTH(new_data); - const char *maybe_end_arg = ""; - if (text_len > 0 && PyUnicode_READ_CHAR(new_data, text_len-1) == ',') { - maybe_end_arg = " end=\" \""; - } - PyObject *error_msg = PyUnicode_FromFormat( - "Missing parentheses in call to 'print'. Did you mean print(%U%s)?", - new_data, maybe_end_arg - ); - Py_DECREF(new_data); - if (error_msg == NULL) - return -1; - - Py_XSETREF(self->msg, error_msg); - return 1; -} - -static int -_check_for_legacy_statements(PySyntaxErrorObject *self, Py_ssize_t start) -{ - /* Return values: - * -1: an error occurred - * 0: nothing happened - * 1: the check triggered & the error message was changed - */ - static PyObject *print_prefix = NULL; - static PyObject *exec_prefix = NULL; - Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text), match; - int kind = PyUnicode_KIND(self->text); - const void *data = PyUnicode_DATA(self->text); - - /* Ignore leading whitespace */ - while (start < text_len) { - Py_UCS4 ch = PyUnicode_READ(kind, data, start); - if (!Py_UNICODE_ISSPACE(ch)) - break; - start++; - } - /* Checking against an empty or whitespace-only part of the string */ - if (start == text_len) { - return 0; - } - - /* Check for legacy print statements */ - if (print_prefix == NULL) { - print_prefix = PyUnicode_InternFromString("print "); - if (print_prefix == NULL) { - return -1; - } - } - match = PyUnicode_Tailmatch(self->text, print_prefix, - start, text_len, -1); - if (match == -1) { - return -1; - } - if (match) { - return _set_legacy_print_statement_msg(self, start); - } - - /* Check for legacy exec statements */ - if (exec_prefix == NULL) { - exec_prefix = PyUnicode_InternFromString("exec "); - if (exec_prefix == NULL) { - return -1; - } - } - match = PyUnicode_Tailmatch(self->text, exec_prefix, start, text_len, -1); - if (match == -1) { - return -1; - } - if (match) { - PyObject *msg = PyUnicode_FromString("Missing parentheses in call " - "to 'exec'"); - if (msg == NULL) { - return -1; - } - Py_XSETREF(self->msg, msg); - return 1; - } - /* Fall back to the default error message */ - return 0; -} - -static int -_report_missing_parentheses(PySyntaxErrorObject *self) -{ - Py_UCS4 left_paren = 40; - Py_ssize_t left_paren_index; - Py_ssize_t text_len = PyUnicode_GET_LENGTH(self->text); - int legacy_check_result = 0; - - /* Skip entirely if there is an opening parenthesis */ - left_paren_index = PyUnicode_FindChar(self->text, left_paren, - 0, text_len, 1); - if (left_paren_index < -1) { - return -1; - } - if (left_paren_index != -1) { - /* Use default error message for any line with an opening paren */ - return 0; - } - /* Handle the simple statement case */ - legacy_check_result = _check_for_legacy_statements(self, 0); - if (legacy_check_result < 0) { - return -1; - - } - if (legacy_check_result == 0) { - /* Handle the one-line complex statement case */ - Py_UCS4 colon = 58; - Py_ssize_t colon_index; - colon_index = PyUnicode_FindChar(self->text, colon, - 0, text_len, 1); - if (colon_index < -1) { - return -1; - } - if (colon_index >= 0 && colon_index < text_len) { - /* Check again, starting from just after the colon */ - if (_check_for_legacy_statements(self, colon_index+1) < 0) { - return -1; - } - } - } - return 0; -} diff --git a/contrib/tools/python3/src/Objects/fileobject.c b/contrib/tools/python3/src/Objects/fileobject.c index 1c6ecaf82c..5a2816f552 100644 --- a/contrib/tools/python3/src/Objects/fileobject.c +++ b/contrib/tools/python3/src/Objects/fileobject.c @@ -223,6 +223,17 @@ PyObject_AsFileDescriptor(PyObject *o) return fd; } +int +_PyLong_FileDescriptor_Converter(PyObject *o, void *ptr) +{ + int fd = PyObject_AsFileDescriptor(o); + if (fd == -1) { + return 0; + } + *(int *)ptr = fd; + return 1; +} + /* ** Py_UniversalNewlineFgets is an fgets variation that understands ** all of \r, \n and \r\n conventions. @@ -314,29 +325,6 @@ typedef struct { int fd; } PyStdPrinter_Object; -static PyObject * -stdprinter_new(PyTypeObject *type, PyObject *args, PyObject *kews) -{ - PyStdPrinter_Object *self; - - assert(type != NULL && type->tp_alloc != NULL); - - self = (PyStdPrinter_Object *) type->tp_alloc(type, 0); - if (self != NULL) { - self->fd = -1; - } - - return (PyObject *) self; -} - -static int -stdprinter_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - PyErr_SetString(PyExc_TypeError, - "cannot create 'stderrprinter' instances"); - return -1; -} - PyObject * PyFile_NewStdPrinter(int fd) { @@ -379,7 +367,7 @@ stdprinter_write(PyStdPrinter_Object *self, PyObject *args) return NULL; } - /* Encode Unicode to UTF-8/surrogateescape */ + /* Encode Unicode to UTF-8/backslashreplace */ str = PyUnicode_AsUTF8AndSize(unicode, &n); if (str == NULL) { PyErr_Clear(); @@ -496,7 +484,7 @@ PyTypeObject PyStdPrinter_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_DISALLOW_INSTANTIATION, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -512,9 +500,9 @@ PyTypeObject PyStdPrinter_Type = { 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - stdprinter_init, /* tp_init */ + 0, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ - stdprinter_new, /* tp_new */ + 0, /* tp_new */ PyObject_Del, /* tp_free */ }; diff --git a/contrib/tools/python3/src/Objects/floatobject.c b/contrib/tools/python3/src/Objects/floatobject.c index 6ac6127ae5..2e02f37f4a 100644 --- a/contrib/tools/python3/src/Objects/floatobject.c +++ b/contrib/tools/python3/src/Objects/floatobject.c @@ -4,7 +4,11 @@ for any kind of float exception without losing portability. */ #include "Python.h" -#include "pycore_dtoa.h" +#include "pycore_dtoa.h" // _Py_dg_dtoa() +#include "pycore_interp.h" // _PyInterpreterState.float_state +#include "pycore_long.h" // _PyLong_GetOne() +#include "pycore_object.h" // _PyObject_Init() +#include "pycore_pystate.h" // _PyInterpreterState_GET() #include <ctype.h> #include <float.h> @@ -16,16 +20,18 @@ class float "PyObject *" "&PyFloat_Type" #include "clinic/floatobject.c.h" -/* Special free list - free_list is a singly-linked list of available PyFloatObjects, linked - via abuse of their ob_type members. -*/ - #ifndef PyFloat_MAXFREELIST -#define PyFloat_MAXFREELIST 100 +# define PyFloat_MAXFREELIST 100 #endif -static int numfree = 0; -static PyFloatObject *free_list = NULL; + + +static struct _Py_float_state * +get_float_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->float_state; +} + double PyFloat_GetMax(void) @@ -59,12 +65,14 @@ static PyStructSequence_Field floatinfo_fields[] = { "is a normalized float"}, {"min_10_exp", "DBL_MIN_10_EXP -- minimum int e such that 10**e is " "a normalized"}, - {"dig", "DBL_DIG -- digits"}, + {"dig", "DBL_DIG -- maximum number of decimal digits that " + "can be faithfully represented in a float"}, {"mant_dig", "DBL_MANT_DIG -- mantissa digits"}, {"epsilon", "DBL_EPSILON -- Difference between 1 and the next " "representable float"}, {"radix", "FLT_RADIX -- radix of exponent"}, - {"rounds", "FLT_ROUNDS -- rounding mode"}, + {"rounds", "FLT_ROUNDS -- rounding mode used for arithmetic " + "operations"}, {0} }; @@ -115,17 +123,23 @@ PyFloat_GetInfo(void) PyObject * PyFloat_FromDouble(double fval) { - PyFloatObject *op = free_list; + struct _Py_float_state *state = get_float_state(); + PyFloatObject *op = state->free_list; if (op != NULL) { - free_list = (PyFloatObject *) Py_TYPE(op); - numfree--; - } else { - op = (PyFloatObject*) PyObject_MALLOC(sizeof(PyFloatObject)); - if (!op) +#ifdef Py_DEBUG + // PyFloat_FromDouble() must not be called after _PyFloat_Fini() + assert(state->numfree != -1); +#endif + state->free_list = (PyFloatObject *) Py_TYPE(op); + state->numfree--; + } + else { + op = PyObject_Malloc(sizeof(PyFloatObject)); + if (!op) { return PyErr_NoMemory(); + } } - /* Inline PyObject_New */ - (void)PyObject_INIT(op, &PyFloat_Type); + _PyObject_Init((PyObject*)op, &PyFloat_Type); op->ob_fval = fval; return (PyObject *) op; } @@ -202,7 +216,7 @@ PyFloat_FromString(PyObject *v) } else { PyErr_Format(PyExc_TypeError, - "float() argument must be a string or a number, not '%.200s'", + "float() argument must be a string or a real number, not '%.200s'", Py_TYPE(v)->tp_name); return NULL; } @@ -217,16 +231,22 @@ static void float_dealloc(PyFloatObject *op) { if (PyFloat_CheckExact(op)) { - if (numfree >= PyFloat_MAXFREELIST) { - PyObject_FREE(op); + struct _Py_float_state *state = get_float_state(); +#ifdef Py_DEBUG + // float_dealloc() must not be called after _PyFloat_Fini() + assert(state->numfree != -1); +#endif + if (state->numfree >= PyFloat_MAXFREELIST) { + PyObject_Free(op); return; } - numfree++; - Py_SET_TYPE(op, (PyTypeObject *)free_list); - free_list = op; + state->numfree++; + Py_SET_TYPE(op, (PyTypeObject *)state->free_list); + state->free_list = op; } - else + else { Py_TYPE(op)->tp_free((PyObject *)op); + } } double @@ -248,7 +268,7 @@ PyFloat_AsDouble(PyObject *op) nb = Py_TYPE(op)->tp_as_number; if (nb == NULL || nb->nb_float == NULL) { if (nb && nb->nb_index) { - PyObject *res = PyNumber_Index(op); + PyObject *res = _PyNumber_Index(op); if (!res) { return -1; } @@ -485,7 +505,7 @@ float_richcompare(PyObject *v, PyObject *w, int op) Py_DECREF(vv); vv = temp; - temp = PyNumber_Or(vv, _PyLong_One); + temp = PyNumber_Or(vv, _PyLong_GetOne()); if (temp == NULL) goto Error; Py_DECREF(vv); @@ -536,7 +556,7 @@ float_richcompare(PyObject *v, PyObject *w, int op) static Py_hash_t float_hash(PyFloatObject *v) { - return _Py_HashDouble(v->ob_fval); + return _Py_HashDouble((PyObject *)v, v->ob_fval); } static PyObject * @@ -1586,7 +1606,7 @@ float_subtype_new(PyTypeObject *type, PyObject *x); /*[clinic input] @classmethod float.__new__ as float_new - x: object(c_default="_PyLong_Zero") = 0 + x: object(c_default="NULL") = 0 / Convert a string or number to a floating point number, if possible. @@ -1594,10 +1614,18 @@ Convert a string or number to a floating point number, if possible. static PyObject * float_new_impl(PyTypeObject *type, PyObject *x) -/*[clinic end generated code: output=ccf1e8dc460ba6ba input=540ee77c204ff87a]*/ +/*[clinic end generated code: output=ccf1e8dc460ba6ba input=f43661b7de03e9d8]*/ { - if (type != &PyFloat_Type) + if (type != &PyFloat_Type) { + if (x == NULL) { + x = _PyLong_GetZero(); + } return float_subtype_new(type, x); /* Wimp out */ + } + + if (x == NULL) { + return PyFloat_FromDouble(0.0); + } /* If it's a string, but not a string subclass, use PyFloat_FromString. */ if (PyUnicode_CheckExact(x)) @@ -1630,6 +1658,24 @@ float_subtype_new(PyTypeObject *type, PyObject *x) return newobj; } +static PyObject * +float_vectorcall(PyObject *type, PyObject * const*args, + size_t nargsf, PyObject *kwnames) +{ + if (!_PyArg_NoKwnames("float", kwnames)) { + return NULL; + } + + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + if (!_PyArg_CheckPositional("float", nargs, 0, 1)) { + return NULL; + } + + PyObject *x = nargs >= 1 ? args[0] : NULL; + return float_new_impl((PyTypeObject *)type, x); +} + + /*[clinic input] float.__getnewargs__ [clinic start generated code]*/ @@ -1899,7 +1945,8 @@ PyTypeObject PyFloat_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ float_new__doc__, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -1918,9 +1965,10 @@ PyTypeObject PyFloat_Type = { 0, /* tp_init */ 0, /* tp_alloc */ float_new, /* tp_new */ + .tp_vectorcall = (vectorcallfunc)float_vectorcall, }; -int +void _PyFloat_Init(void) { /* We attempt to determine if this machine is using IEEE @@ -1968,41 +2016,52 @@ _PyFloat_Init(void) double_format = detected_double_format; float_format = detected_float_format; +} +int +_PyFloat_InitTypes(void) +{ /* Init float info */ if (FloatInfoType.tp_name == NULL) { if (PyStructSequence_InitType2(&FloatInfoType, &floatinfo_desc) < 0) { - return 0; + return -1; } } - return 1; + return 0; } void -_PyFloat_ClearFreeList(void) +_PyFloat_ClearFreeList(PyInterpreterState *interp) { - PyFloatObject *f = free_list, *next; - for (; f; f = next) { - next = (PyFloatObject*) Py_TYPE(f); - PyObject_FREE(f); - } - free_list = NULL; - numfree = 0; + struct _Py_float_state *state = &interp->float_state; + PyFloatObject *f = state->free_list; + while (f != NULL) { + PyFloatObject *next = (PyFloatObject*) Py_TYPE(f); + PyObject_Free(f); + f = next; + } + state->free_list = NULL; + state->numfree = 0; } void -_PyFloat_Fini(void) +_PyFloat_Fini(PyInterpreterState *interp) { - _PyFloat_ClearFreeList(); + _PyFloat_ClearFreeList(interp); +#ifdef Py_DEBUG + struct _Py_float_state *state = &interp->float_state; + state->numfree = -1; +#endif } /* Print summary info about the state of the optimized allocator */ void _PyFloat_DebugMallocStats(FILE *out) { + struct _Py_float_state *state = get_float_state(); _PyDebugAllocatorStats(out, "free PyFloatObject", - numfree, sizeof(PyFloatObject)); + state->numfree, sizeof(PyFloatObject)); } diff --git a/contrib/tools/python3/src/Objects/frameobject.c b/contrib/tools/python3/src/Objects/frameobject.c index 4ae17bcfc2..d02cf9d3ba 100644 --- a/contrib/tools/python3/src/Objects/frameobject.c +++ b/contrib/tools/python3/src/Objects/frameobject.c @@ -1,27 +1,34 @@ /* Frame object implementation */ #include "Python.h" -#include "pycore_object.h" -#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() +#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals() +#include "pycore_moduleobject.h" // _PyModule_GetDict() +#include "pycore_object.h" // _PyObject_GC_UNTRACK() -#include "code.h" -#include "frameobject.h" -#include "opcode.h" +#include "frameobject.h" // PyFrameObject +#include "opcode.h" // EXTENDED_ARG #include "structmember.h" // PyMemberDef #define OFF(x) offsetof(PyFrameObject, x) static PyMemberDef frame_memberlist[] = { {"f_back", T_OBJECT, OFF(f_back), READONLY}, - {"f_code", T_OBJECT, OFF(f_code), READONLY|READ_RESTRICTED}, + {"f_code", T_OBJECT, OFF(f_code), READONLY|PY_AUDIT_READ}, {"f_builtins", T_OBJECT, OFF(f_builtins), READONLY}, {"f_globals", T_OBJECT, OFF(f_globals), READONLY}, - {"f_lasti", T_INT, OFF(f_lasti), READONLY}, {"f_trace_lines", T_BOOL, OFF(f_trace_lines), 0}, {"f_trace_opcodes", T_BOOL, OFF(f_trace_opcodes), 0}, {NULL} /* Sentinel */ }; +static struct _Py_frame_state * +get_frame_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->frame; +} + + static PyObject * frame_getlocals(PyFrameObject *f, void *closure) { @@ -35,18 +42,33 @@ int PyFrame_GetLineNumber(PyFrameObject *f) { assert(f != NULL); - if (f->f_trace) { + if (f->f_lineno != 0) { return f->f_lineno; } else { - return PyCode_Addr2Line(f->f_code, f->f_lasti); + return PyCode_Addr2Line(f->f_code, f->f_lasti*sizeof(_Py_CODEUNIT)); } } static PyObject * frame_getlineno(PyFrameObject *f, void *closure) { - return PyLong_FromLong(PyFrame_GetLineNumber(f)); + int lineno = PyFrame_GetLineNumber(f); + if (lineno < 0) { + Py_RETURN_NONE; + } + else { + return PyLong_FromLong(lineno); + } +} + +static PyObject * +frame_getlasti(PyFrameObject *f, void *closure) +{ + if (f->f_lasti < 0) { + return PyLong_FromLong(-1); + } + return PyLong_FromLong(f->f_lasti*sizeof(_Py_CODEUNIT)); } @@ -128,7 +150,7 @@ markblocks(PyCodeObject *code_obj, int len) case POP_JUMP_IF_FALSE: case POP_JUMP_IF_TRUE: case JUMP_IF_NOT_EXC_MATCH: - j = get_arg(code, i) / sizeof(_Py_CODEUNIT); + j = get_arg(code, i); assert(j < len); if (blocks[j] == -1 && j < i) { todo = 1; @@ -138,7 +160,7 @@ markblocks(PyCodeObject *code_obj, int len) blocks[i+1] = block_stack; break; case JUMP_ABSOLUTE: - j = get_arg(code, i) / sizeof(_Py_CODEUNIT); + j = get_arg(code, i); assert(j < len); if (blocks[j] == -1 && j < i) { todo = 1; @@ -147,7 +169,7 @@ markblocks(PyCodeObject *code_obj, int len) blocks[j] = block_stack; break; case SETUP_FINALLY: - j = get_arg(code, i) / sizeof(_Py_CODEUNIT) + i + 1; + j = get_arg(code, i) + i + 1; assert(j < len); except_stack = push_block(block_stack, Except); assert(blocks[j] == -1 || blocks[j] == except_stack); @@ -157,7 +179,7 @@ markblocks(PyCodeObject *code_obj, int len) break; case SETUP_WITH: case SETUP_ASYNC_WITH: - j = get_arg(code, i) / sizeof(_Py_CODEUNIT) + i + 1; + j = get_arg(code, i) + i + 1; assert(j < len); except_stack = push_block(block_stack, Except); assert(blocks[j] == -1 || blocks[j] == except_stack); @@ -166,7 +188,7 @@ markblocks(PyCodeObject *code_obj, int len) blocks[i+1] = block_stack; break; case JUMP_FORWARD: - j = get_arg(code, i) / sizeof(_Py_CODEUNIT) + i + 1; + j = get_arg(code, i) + i + 1; assert(j < len); assert(blocks[j] == -1 || blocks[j] == block_stack); blocks[j] = block_stack; @@ -179,7 +201,7 @@ markblocks(PyCodeObject *code_obj, int len) case FOR_ITER: blocks[i+1] = block_stack; block_stack = pop_block(block_stack); - j = get_arg(code, i) / sizeof(_Py_CODEUNIT) + i + 1; + j = get_arg(code, i) + i + 1; assert(j < len); assert(blocks[j] == -1 || blocks[j] == block_stack); blocks[j] = block_stack; @@ -240,36 +262,22 @@ explain_incompatible_block_stack(int64_t to_stack) static int * marklines(PyCodeObject *code, int len) { + PyCodeAddressRange bounds; + _PyCode_InitAddressRange(code, &bounds); + assert (bounds.ar_end == 0); + int *linestarts = PyMem_New(int, len); if (linestarts == NULL) { return NULL; } - Py_ssize_t size = PyBytes_GET_SIZE(code->co_lnotab) / 2; - unsigned char *p = (unsigned char*)PyBytes_AS_STRING(code->co_lnotab); - int line = code->co_firstlineno; - int addr = 0; - int index = 0; - while (--size >= 0) { - addr += *p++; - if (index*2 < addr) { - linestarts[index++] = line; - } - while (index*2 < addr) { - linestarts[index++] = -1; - if (index >= len) { - break; - } - } - line += (signed char)*p; - p++; - } - if (index < len) { - linestarts[index++] = line; + for (int i = 0; i < len; i++) { + linestarts[i] = -1; } - while (index < len) { - linestarts[index++] = -1; + + while (PyLineTable_NextAddressRange(&bounds)) { + assert(bounds.ar_start/(int)sizeof(_Py_CODEUNIT) < len); + linestarts[bounds.ar_start/sizeof(_Py_CODEUNIT)] = bounds.ar_line; } - assert(index == len); return linestarts; } @@ -291,17 +299,20 @@ first_line_not_before(int *lines, int len, int line) static void frame_stack_pop(PyFrameObject *f) { - PyObject *v = (*--f->f_stacktop); + assert(f->f_stackdepth >= 0); + f->f_stackdepth--; + PyObject *v = f->f_valuestack[f->f_stackdepth]; Py_DECREF(v); } static void frame_block_unwind(PyFrameObject *f) { + assert(f->f_stackdepth >= 0); assert(f->f_iblock > 0); f->f_iblock--; PyTryBlock *b = &f->f_blockstack[f->f_iblock]; - intptr_t delta = (f->f_stacktop - f->f_valuestack) - b->b_level; + intptr_t delta = f->f_stackdepth - b->b_level; while (delta > 0) { frame_stack_pop(f); delta--; @@ -343,33 +354,36 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore return -1; } - /* Upon the 'call' trace event of a new frame, f->f_lasti is -1 and - * f->f_trace is NULL, check first on the first condition. - * Forbidding jumps from the 'call' event of a new frame is a side effect - * of allowing to set f_lineno only from trace functions. */ - if (f->f_lasti == -1) { - PyErr_Format(PyExc_ValueError, + /* + * This code preserves the historical restrictions on + * setting the line number of a frame. + * Jumps are forbidden on a 'return' trace event (except after a yield). + * Jumps from 'call' trace events are also forbidden. + * In addition, jumps are forbidden when not tracing, + * as this is a debugging feature. + */ + switch(f->f_state) { + case FRAME_CREATED: + PyErr_Format(PyExc_ValueError, "can't jump from the 'call' trace event of a new frame"); - return -1; - } - - /* You can only do this from within a trace function, not via - * _getframe or similar hackery. */ - if (!f->f_trace) { - PyErr_Format(PyExc_ValueError, - "f_lineno can only be set by a trace function"); - return -1; - } - - /* Forbid jumps upon a 'return' trace event (except after executing a - * YIELD_VALUE or YIELD_FROM opcode, f_stacktop is not NULL in that case) - * and upon an 'exception' trace event. - * Jumps from 'call' trace events have already been forbidden above for new - * frames, so this check does not change anything for 'call' events. */ - if (f->f_stacktop == NULL) { - PyErr_SetString(PyExc_ValueError, + return -1; + case FRAME_RETURNED: + case FRAME_UNWINDING: + case FRAME_RAISED: + case FRAME_CLEARED: + PyErr_SetString(PyExc_ValueError, "can only jump from a 'line' trace event"); - return -1; + return -1; + case FRAME_EXECUTING: + case FRAME_SUSPENDED: + /* You can only do this from within a trace function, not via + * _getframe or similar hackery. */ + if (!f->f_trace) { + PyErr_Format(PyExc_ValueError, + "f_lineno can only be set by a trace function"); + return -1; + } + break; } int new_lineno; @@ -423,7 +437,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore int64_t target_block_stack = -1; int64_t best_block_stack = -1; int best_addr = -1; - int64_t start_block_stack = blocks[f->f_lasti/sizeof(_Py_CODEUNIT)]; + int64_t start_block_stack = blocks[f->f_lasti]; const char *msg = "cannot find bytecode for specified line"; for (int i = 0; i < len; i++) { if (lines[i] == new_lineno) { @@ -432,7 +446,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore msg = NULL; if (target_block_stack > best_block_stack) { best_block_stack = target_block_stack; - best_addr = i*sizeof(_Py_CODEUNIT); + best_addr = i; } } else if (msg) { @@ -475,8 +489,8 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore start_block_stack = pop_block(start_block_stack); } - /* Finally set the new f_lineno and f_lasti and return OK. */ - f->f_lineno = new_lineno; + /* Finally set the new f_lasti and return OK. */ + f->f_lineno = 0; f->f_lasti = best_addr; return 0; } @@ -497,11 +511,9 @@ frame_gettrace(PyFrameObject *f, void *closure) static int frame_settrace(PyFrameObject *f, PyObject* v, void *closure) { - /* We rely on f_lineno being accurate when f_trace is set. */ - f->f_lineno = PyFrame_GetLineNumber(f); - - if (v == Py_None) + if (v == Py_None) { v = NULL; + } Py_XINCREF(v); Py_XSETREF(f->f_trace, v); @@ -514,6 +526,7 @@ static PyGetSetDef frame_getsetlist[] = { {"f_lineno", (getter)frame_getlineno, (setter)frame_setlineno, NULL}, {"f_trace", (getter)frame_gettrace, (setter)frame_settrace, NULL}, + {"f_lasti", (getter)frame_getlasti, NULL, NULL}, {0} }; @@ -561,31 +574,25 @@ static PyGetSetDef frame_getsetlist[] = { /* max value for numfree */ #define PyFrame_MAXFREELIST 200 -#if PyFrame_MAXFREELIST > 0 -static PyFrameObject *free_list = NULL; -static int numfree = 0; /* number of frames currently in free_list */ -#endif - static void _Py_HOT_FUNCTION frame_dealloc(PyFrameObject *f) { - PyObject **p, **valuestack; - PyCodeObject *co; - - if (_PyObject_GC_IS_TRACKED(f)) + if (_PyObject_GC_IS_TRACKED(f)) { _PyObject_GC_UNTRACK(f); + } Py_TRASHCAN_BEGIN(f, frame_dealloc); /* Kill all local variables */ - valuestack = f->f_valuestack; - for (p = f->f_localsplus; p < valuestack; p++) + PyObject **valuestack = f->f_valuestack; + for (PyObject **p = f->f_localsplus; p < valuestack; p++) { Py_CLEAR(*p); + } /* Free stack */ - if (f->f_stacktop != NULL) { - for (p = valuestack; p < f->f_stacktop; p++) - Py_XDECREF(*p); + for (int i = 0; i < f->f_stackdepth; i++) { + Py_XDECREF(f->f_valuestack[i]); } + f->f_stackdepth = 0; Py_XDECREF(f->f_back); Py_DECREF(f->f_builtins); @@ -593,19 +600,24 @@ frame_dealloc(PyFrameObject *f) Py_CLEAR(f->f_locals); Py_CLEAR(f->f_trace); - co = f->f_code; + PyCodeObject *co = f->f_code; if (co->co_zombieframe == NULL) { co->co_zombieframe = f; } -#if PyFrame_MAXFREELIST > 0 - else if (numfree < PyFrame_MAXFREELIST) { - ++numfree; - f->f_back = free_list; - free_list = f; - } -#endif else { - PyObject_GC_Del(f); + struct _Py_frame_state *state = get_frame_state(); +#ifdef Py_DEBUG + // frame_dealloc() must not be called after _PyFrame_Fini() + assert(state->numfree != -1); +#endif + if (state->numfree < PyFrame_MAXFREELIST) { + ++state->numfree; + f->f_back = state->free_list; + state->free_list = f; + } + else { + PyObject_GC_Del(f); + } } Py_DECREF(co); @@ -638,10 +650,8 @@ frame_traverse(PyFrameObject *f, visitproc visit, void *arg) } /* stack */ - if (f->f_stacktop != NULL) { - for (PyObject **p = f->f_valuestack; p < f->f_stacktop; p++) { - Py_VISIT(*p); - } + for (int i = 0; i < f->f_stackdepth; i++) { + Py_VISIT(f->f_valuestack[i]); } return 0; } @@ -654,9 +664,7 @@ frame_tp_clear(PyFrameObject *f) * frame may also point to this frame, believe itself to still be * active, and try cleaning up this frame again. */ - PyObject **oldtop = f->f_stacktop; - f->f_stacktop = NULL; - f->f_executing = 0; + f->f_state = FRAME_CLEARED; Py_CLEAR(f->f_trace); @@ -667,18 +675,17 @@ frame_tp_clear(PyFrameObject *f) } /* stack */ - if (oldtop != NULL) { - for (PyObject **p = f->f_valuestack; p < oldtop; p++) { - Py_CLEAR(*p); - } + for (int i = 0; i < f->f_stackdepth; i++) { + Py_CLEAR(f->f_valuestack[i]); } + f->f_stackdepth = 0; return 0; } static PyObject * frame_clear(PyFrameObject *f, PyObject *Py_UNUSED(ignored)) { - if (f->f_executing) { + if (_PyFrame_IsExecuting(f)) { PyErr_SetString(PyExc_RuntimeError, "cannot clear an executing frame"); return NULL; @@ -770,9 +777,7 @@ _Py_IDENTIFIER(__builtins__); static inline PyFrameObject* frame_alloc(PyCodeObject *code) { - PyFrameObject *f; - - f = code->co_zombieframe; + PyFrameObject *f = code->co_zombieframe; if (f != NULL) { code->co_zombieframe = NULL; _Py_NewReference((PyObject *)f); @@ -783,21 +788,23 @@ frame_alloc(PyCodeObject *code) Py_ssize_t ncells = PyTuple_GET_SIZE(code->co_cellvars); Py_ssize_t nfrees = PyTuple_GET_SIZE(code->co_freevars); Py_ssize_t extras = code->co_stacksize + code->co_nlocals + ncells + nfrees; -#if PyFrame_MAXFREELIST > 0 - if (free_list == NULL) -#endif + struct _Py_frame_state *state = get_frame_state(); + if (state->free_list == NULL) { f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, extras); if (f == NULL) { return NULL; } } -#if PyFrame_MAXFREELIST > 0 else { - assert(numfree > 0); - --numfree; - f = free_list; - free_list = free_list->f_back; +#ifdef Py_DEBUG + // frame_alloc() must not be called after _PyFrame_Fini() + assert(state->numfree != -1); +#endif + assert(state->numfree > 0); + --state->numfree; + f = state->free_list; + state->free_list = state->free_list->f_back; if (Py_SIZE(f) < extras) { PyFrameObject *new_f = PyObject_GC_Resize(PyFrameObject, f, extras); if (new_f == NULL) { @@ -808,132 +815,72 @@ frame_alloc(PyCodeObject *code) } _Py_NewReference((PyObject *)f); } -#endif - f->f_code = code; extras = code->co_nlocals + ncells + nfrees; f->f_valuestack = f->f_localsplus + extras; - for (Py_ssize_t i=0; i<extras; i++) { + for (Py_ssize_t i=0; i < extras; i++) { f->f_localsplus[i] = NULL; } - f->f_locals = NULL; - f->f_trace = NULL; return f; } -static inline PyObject * -frame_get_builtins(PyFrameObject *back, PyObject *globals) -{ - PyObject *builtins; - - if (back != NULL && back->f_globals == globals) { - /* If we share the globals, we share the builtins. - Save a lookup and a call. */ - builtins = back->f_builtins; - assert(builtins != NULL); - Py_INCREF(builtins); - return builtins; - } - - builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__); - if (builtins != NULL && PyModule_Check(builtins)) { - builtins = PyModule_GetDict(builtins); - assert(builtins != NULL); - } - if (builtins != NULL) { - Py_INCREF(builtins); - return builtins; - } - - if (PyErr_Occurred()) { - return NULL; - } - - /* No builtins! Make up a minimal one. - Give them 'None', at least. */ - builtins = PyDict_New(); - if (builtins == NULL) { - return NULL; - } - if (PyDict_SetItemString(builtins, "None", Py_None) < 0) { - Py_DECREF(builtins); - return NULL; - } - return builtins; -} - - PyFrameObject* _Py_HOT_FUNCTION -_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code, - PyObject *globals, PyObject *locals) +_PyFrame_New_NoTrack(PyThreadState *tstate, PyFrameConstructor *con, PyObject *locals) { -#ifdef Py_DEBUG - if (code == NULL || globals == NULL || !PyDict_Check(globals) || - (locals != NULL && !PyMapping_Check(locals))) { - PyErr_BadInternalCall(); - return NULL; - } -#endif - - PyFrameObject *back = tstate->frame; - PyObject *builtins = frame_get_builtins(back, globals); - if (builtins == NULL) { - return NULL; - } + assert(con != NULL); + assert(con->fc_globals != NULL); + assert(con->fc_builtins != NULL); + assert(con->fc_code != NULL); + assert(locals == NULL || PyMapping_Check(locals)); - PyFrameObject *f = frame_alloc(code); + PyFrameObject *f = frame_alloc((PyCodeObject *)con->fc_code); if (f == NULL) { - Py_DECREF(builtins); return NULL; } - f->f_stacktop = f->f_valuestack; - f->f_builtins = builtins; - Py_XINCREF(back); - f->f_back = back; - Py_INCREF(code); - Py_INCREF(globals); - f->f_globals = globals; - /* Most functions have CO_NEWLOCALS and CO_OPTIMIZED set. */ - if ((code->co_flags & (CO_NEWLOCALS | CO_OPTIMIZED)) == - (CO_NEWLOCALS | CO_OPTIMIZED)) - ; /* f_locals = NULL; will be set by PyFrame_FastToLocals() */ - else if (code->co_flags & CO_NEWLOCALS) { - locals = PyDict_New(); - if (locals == NULL) { - Py_DECREF(f); - return NULL; - } - f->f_locals = locals; - } - else { - if (locals == NULL) - locals = globals; - Py_INCREF(locals); - f->f_locals = locals; - } - + f->f_back = (PyFrameObject*)Py_XNewRef(tstate->frame); + f->f_code = (PyCodeObject *)Py_NewRef(con->fc_code); + f->f_builtins = Py_NewRef(con->fc_builtins); + f->f_globals = Py_NewRef(con->fc_globals); + f->f_locals = Py_XNewRef(locals); + // f_valuestack initialized by frame_alloc() + f->f_trace = NULL; + f->f_stackdepth = 0; + f->f_trace_lines = 1; + f->f_trace_opcodes = 0; + f->f_gen = NULL; f->f_lasti = -1; - f->f_lineno = code->co_firstlineno; + f->f_lineno = 0; f->f_iblock = 0; - f->f_executing = 0; - f->f_gen = NULL; - f->f_trace_opcodes = 0; - f->f_trace_lines = 1; - - assert(f->f_code != NULL); - + f->f_state = FRAME_CREATED; + // f_blockstack and f_localsplus initialized by frame_alloc() return f; } +/* Legacy API */ PyFrameObject* PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, PyObject *locals) { - PyFrameObject *f = _PyFrame_New_NoTrack(tstate, code, globals, locals); - if (f) + PyObject *builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref + if (builtins == NULL) { + return NULL; + } + PyFrameConstructor desc = { + .fc_globals = globals, + .fc_builtins = builtins, + .fc_name = code->co_name, + .fc_qualname = code->co_name, + .fc_code = (PyObject *)code, + .fc_defaults = NULL, + .fc_kwdefaults = NULL, + .fc_closure = NULL + }; + PyFrameObject *f = _PyFrame_New_NoTrack(tstate, &desc, locals); + if (f) { _PyObject_GC_TRACK(f); + } return f; } @@ -1177,34 +1124,36 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear) /* Clear out the free list */ void -_PyFrame_ClearFreeList(void) +_PyFrame_ClearFreeList(PyInterpreterState *interp) { -#if PyFrame_MAXFREELIST > 0 - while (free_list != NULL) { - PyFrameObject *f = free_list; - free_list = free_list->f_back; + struct _Py_frame_state *state = &interp->frame; + while (state->free_list != NULL) { + PyFrameObject *f = state->free_list; + state->free_list = state->free_list->f_back; PyObject_GC_Del(f); - --numfree; + --state->numfree; } - assert(numfree == 0); -#endif + assert(state->numfree == 0); } void -_PyFrame_Fini(void) +_PyFrame_Fini(PyInterpreterState *interp) { - _PyFrame_ClearFreeList(); + _PyFrame_ClearFreeList(interp); +#ifdef Py_DEBUG + struct _Py_frame_state *state = &interp->frame; + state->numfree = -1; +#endif } /* Print summary info about the state of the optimized allocator */ void _PyFrame_DebugMallocStats(FILE *out) { -#if PyFrame_MAXFREELIST > 0 + struct _Py_frame_state *state = get_frame_state(); _PyDebugAllocatorStats(out, "free PyFrameObject", - numfree, sizeof(PyFrameObject)); -#endif + state->numfree, sizeof(PyFrameObject)); } @@ -1227,3 +1176,21 @@ PyFrame_GetBack(PyFrameObject *frame) Py_XINCREF(back); return back; } + +PyObject* +_PyEval_BuiltinsFromGlobals(PyThreadState *tstate, PyObject *globals) +{ + PyObject *builtins = _PyDict_GetItemIdWithError(globals, &PyId___builtins__); + if (builtins) { + if (PyModule_Check(builtins)) { + builtins = _PyModule_GetDict(builtins); + assert(builtins != NULL); + } + return builtins; + } + if (PyErr_Occurred()) { + return NULL; + } + + return _PyEval_GetBuiltins(tstate); +} diff --git a/contrib/tools/python3/src/Objects/funcobject.c b/contrib/tools/python3/src/Objects/funcobject.c index 2c60275d90..801478ade2 100644 --- a/contrib/tools/python3/src/Objects/funcobject.c +++ b/contrib/tools/python3/src/Objects/funcobject.c @@ -2,77 +2,94 @@ /* Function object implementation */ #include "Python.h" -#include "pycore_object.h" -#include "pycore_tupleobject.h" -#include "code.h" +#include "pycore_ceval.h" // _PyEval_BuiltinsFromGlobals() +#include "pycore_object.h" // _PyObject_GC_UNTRACK() +#include "pycore_pyerrors.h" // _PyErr_Occurred() #include "structmember.h" // PyMemberDef PyObject * PyFunction_NewWithQualName(PyObject *code, PyObject *globals, PyObject *qualname) { - PyFunctionObject *op; - PyObject *doc, *consts, *module; - static PyObject *__name__ = NULL; + assert(globals != NULL); + assert(PyDict_Check(globals)); + Py_INCREF(globals); - if (__name__ == NULL) { - __name__ = PyUnicode_InternFromString("__name__"); - if (__name__ == NULL) - return NULL; + PyThreadState *tstate = _PyThreadState_GET(); + + PyCodeObject *code_obj = (PyCodeObject *)code; + Py_INCREF(code_obj); + + PyObject *name = code_obj->co_name; + assert(name != NULL); + Py_INCREF(name); + if (!qualname) { + qualname = name; } + Py_INCREF(qualname); - /* __module__: If module name is in globals, use it. - Otherwise, use None. */ - module = PyDict_GetItemWithError(globals, __name__); - if (module) { - Py_INCREF(module); + PyObject *consts = code_obj->co_consts; + assert(PyTuple_Check(consts)); + PyObject *doc; + if (PyTuple_Size(consts) >= 1) { + doc = PyTuple_GetItem(consts, 0); + if (!PyUnicode_Check(doc)) { + doc = Py_None; + } } - else if (PyErr_Occurred()) { - return NULL; + else { + doc = Py_None; + } + Py_INCREF(doc); + + // __module__: Use globals['__name__'] if it exists, or NULL. + _Py_IDENTIFIER(__name__); + PyObject *module = _PyDict_GetItemIdWithError(globals, &PyId___name__); + PyObject *builtins = NULL; + if (module == NULL && _PyErr_Occurred(tstate)) { + goto error; + } + Py_XINCREF(module); + + builtins = _PyEval_BuiltinsFromGlobals(tstate, globals); // borrowed ref + if (builtins == NULL) { + goto error; } + Py_INCREF(builtins); - op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type); + PyFunctionObject *op = PyObject_GC_New(PyFunctionObject, &PyFunction_Type); if (op == NULL) { - Py_XDECREF(module); - return NULL; + goto error; } /* Note: No failures from this point on, since func_dealloc() does not expect a partially-created object. */ - op->func_weakreflist = NULL; - Py_INCREF(code); - op->func_code = code; - Py_INCREF(globals); op->func_globals = globals; - op->func_name = ((PyCodeObject *)code)->co_name; - Py_INCREF(op->func_name); - op->func_defaults = NULL; /* No default arguments */ - op->func_kwdefaults = NULL; /* No keyword only defaults */ + op->func_builtins = builtins; + op->func_name = name; + op->func_qualname = qualname; + op->func_code = (PyObject*)code_obj; + op->func_defaults = NULL; // No default positional arguments + op->func_kwdefaults = NULL; // No default keyword arguments op->func_closure = NULL; - op->vectorcall = _PyFunction_Vectorcall; - op->func_module = module; - - consts = ((PyCodeObject *)code)->co_consts; - if (PyTuple_Size(consts) >= 1) { - doc = PyTuple_GetItem(consts, 0); - if (!PyUnicode_Check(doc)) - doc = Py_None; - } - else - doc = Py_None; - Py_INCREF(doc); op->func_doc = doc; - op->func_dict = NULL; + op->func_weakreflist = NULL; + op->func_module = module; op->func_annotations = NULL; - - if (qualname) - op->func_qualname = qualname; - else - op->func_qualname = op->func_name; - Py_INCREF(op->func_qualname); + op->vectorcall = _PyFunction_Vectorcall; _PyObject_GC_TRACK(op); return (PyObject *)op; + +error: + Py_DECREF(globals); + Py_DECREF(code_obj); + Py_DECREF(name); + Py_DECREF(qualname); + Py_DECREF(doc); + Py_XDECREF(module); + Py_XDECREF(builtins); + return NULL; } PyObject * @@ -204,6 +221,37 @@ PyFunction_SetClosure(PyObject *op, PyObject *closure) return 0; } +static PyObject * +func_get_annotation_dict(PyFunctionObject *op) +{ + if (op->func_annotations == NULL) { + return NULL; + } + if (PyTuple_CheckExact(op->func_annotations)) { + PyObject *ann_tuple = op->func_annotations; + PyObject *ann_dict = PyDict_New(); + if (ann_dict == NULL) { + return NULL; + } + + assert(PyTuple_GET_SIZE(ann_tuple) % 2 == 0); + + for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(ann_tuple); i += 2) { + int err = PyDict_SetItem(ann_dict, + PyTuple_GET_ITEM(ann_tuple, i), + PyTuple_GET_ITEM(ann_tuple, i + 1)); + + if (err < 0) { + return NULL; + } + } + Py_SETREF(op->func_annotations, ann_dict); + } + Py_INCREF(op->func_annotations); + assert(PyDict_Check(op->func_annotations)); + return op->func_annotations; +} + PyObject * PyFunction_GetAnnotations(PyObject *op) { @@ -211,7 +259,7 @@ PyFunction_GetAnnotations(PyObject *op) PyErr_BadInternalCall(); return NULL; } - return ((PyFunctionObject *) op) -> func_annotations; + return func_get_annotation_dict((PyFunctionObject *)op); } int @@ -244,6 +292,7 @@ static PyMemberDef func_memberlist[] = { {"__doc__", T_OBJECT, OFF(func_doc), 0}, {"__globals__", T_OBJECT, OFF(func_globals), READONLY}, {"__module__", T_OBJECT, OFF(func_module), 0}, + {"__builtins__", T_OBJECT, OFF(func_builtins), READONLY}, {NULL} /* Sentinel */ }; @@ -425,8 +474,7 @@ func_get_annotations(PyFunctionObject *op, void *Py_UNUSED(ignored)) if (op->func_annotations == NULL) return NULL; } - Py_INCREF(op->func_annotations); - return op->func_annotations; + return func_get_annotation_dict(op); } static int @@ -550,9 +598,9 @@ func_new_impl(PyTypeObject *type, PyCodeObject *code, PyObject *globals, newfunc = (PyFunctionObject *)PyFunction_New((PyObject *)code, globals); - if (newfunc == NULL) + if (newfunc == NULL) { return NULL; - + } if (name != Py_None) { Py_INCREF(name); Py_SETREF(newfunc->func_name, name); @@ -574,15 +622,16 @@ func_clear(PyFunctionObject *op) { Py_CLEAR(op->func_code); Py_CLEAR(op->func_globals); - Py_CLEAR(op->func_module); + Py_CLEAR(op->func_builtins); Py_CLEAR(op->func_name); + Py_CLEAR(op->func_qualname); + Py_CLEAR(op->func_module); Py_CLEAR(op->func_defaults); Py_CLEAR(op->func_kwdefaults); Py_CLEAR(op->func_doc); Py_CLEAR(op->func_dict); Py_CLEAR(op->func_closure); Py_CLEAR(op->func_annotations); - Py_CLEAR(op->func_qualname); return 0; } @@ -601,7 +650,7 @@ static PyObject* func_repr(PyFunctionObject *op) { return PyUnicode_FromFormat("<function %U at %p>", - op->func_qualname, op); + op->func_qualname, op); } static int @@ -609,6 +658,7 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg) { Py_VISIT(f->func_code); Py_VISIT(f->func_globals); + Py_VISIT(f->func_builtins); Py_VISIT(f->func_module); Py_VISIT(f->func_defaults); Py_VISIT(f->func_kwdefaults); @@ -676,6 +726,50 @@ PyTypeObject PyFunction_Type = { }; +static int +functools_copy_attr(PyObject *wrapper, PyObject *wrapped, PyObject *name) +{ + PyObject *value = PyObject_GetAttr(wrapped, name); + if (value == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) { + PyErr_Clear(); + return 0; + } + return -1; + } + + int res = PyObject_SetAttr(wrapper, name, value); + Py_DECREF(value); + return res; +} + +// Similar to functools.wraps(wrapper, wrapped) +static int +functools_wraps(PyObject *wrapper, PyObject *wrapped) +{ +#define COPY_ATTR(ATTR) \ + do { \ + _Py_IDENTIFIER(ATTR); \ + PyObject *attr = _PyUnicode_FromId(&PyId_ ## ATTR); \ + if (attr == NULL) { \ + return -1; \ + } \ + if (functools_copy_attr(wrapper, wrapped, attr) < 0) { \ + return -1; \ + } \ + } while (0) \ + + COPY_ATTR(__module__); + COPY_ATTR(__name__); + COPY_ATTR(__qualname__); + COPY_ATTR(__doc__); + COPY_ATTR(__annotations__); + return 0; + +#undef COPY_ATTR +} + + /* Class method object */ /* A class method receives the class as implicit first argument, @@ -742,7 +836,7 @@ cm_descr_get(PyObject *self, PyObject *obj, PyObject *type) type = (PyObject *)(Py_TYPE(obj)); if (Py_TYPE(cm->cm_callable)->tp_descr_get != NULL) { return Py_TYPE(cm->cm_callable)->tp_descr_get(cm->cm_callable, type, - NULL); + type); } return PyMethod_New(cm->cm_callable, type); } @@ -759,11 +853,16 @@ cm_init(PyObject *self, PyObject *args, PyObject *kwds) return -1; Py_INCREF(callable); Py_XSETREF(cm->cm_callable, callable); + + if (functools_wraps((PyObject *)cm, cm->cm_callable) < 0) { + return -1; + } return 0; } static PyMemberDef cm_memberlist[] = { {"__func__", T_OBJECT, offsetof(classmethod, cm_callable), READONLY}, + {"__wrapped__", T_OBJECT, offsetof(classmethod, cm_callable), READONLY}, {NULL} /* Sentinel */ }; @@ -782,13 +881,17 @@ cm_get___isabstractmethod__(classmethod *cm, void *closure) static PyGetSetDef cm_getsetlist[] = { {"__isabstractmethod__", - (getter)cm_get___isabstractmethod__, NULL, - NULL, - NULL}, + (getter)cm_get___isabstractmethod__, NULL, NULL, NULL}, {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, NULL, NULL}, {NULL} /* Sentinel */ }; +static PyObject* +cm_repr(classmethod *cm) +{ + return PyUnicode_FromFormat("<classmethod(%R)>", cm->cm_callable); +} + PyDoc_STRVAR(classmethod_doc, "classmethod(function) -> method\n\ \n\ @@ -821,7 +924,7 @@ PyTypeObject PyClassMethod_Type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - 0, /* tp_repr */ + (reprfunc)cm_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -941,11 +1044,23 @@ sm_init(PyObject *self, PyObject *args, PyObject *kwds) return -1; Py_INCREF(callable); Py_XSETREF(sm->sm_callable, callable); + + if (functools_wraps((PyObject *)sm, sm->sm_callable) < 0) { + return -1; + } return 0; } +static PyObject* +sm_call(PyObject *callable, PyObject *args, PyObject *kwargs) +{ + staticmethod *sm = (staticmethod *)callable; + return PyObject_Call(sm->sm_callable, args, kwargs); +} + static PyMemberDef sm_memberlist[] = { {"__func__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY}, + {"__wrapped__", T_OBJECT, offsetof(staticmethod, sm_callable), READONLY}, {NULL} /* Sentinel */ }; @@ -964,13 +1079,17 @@ sm_get___isabstractmethod__(staticmethod *sm, void *closure) static PyGetSetDef sm_getsetlist[] = { {"__isabstractmethod__", - (getter)sm_get___isabstractmethod__, NULL, - NULL, - NULL}, + (getter)sm_get___isabstractmethod__, NULL, NULL, NULL}, {"__dict__", PyObject_GenericGetDict, PyObject_GenericSetDict, NULL, NULL}, {NULL} /* Sentinel */ }; +static PyObject* +sm_repr(staticmethod *sm) +{ + return PyUnicode_FromFormat("<staticmethod(%R)>", sm->sm_callable); +} + PyDoc_STRVAR(staticmethod_doc, "staticmethod(function) -> method\n\ \n\ @@ -1001,12 +1120,12 @@ PyTypeObject PyStaticMethod_Type = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ - 0, /* tp_repr */ + (reprfunc)sm_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ - 0, /* tp_call */ + sm_call, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ diff --git a/contrib/tools/python3/src/Objects/genericaliasobject.c b/contrib/tools/python3/src/Objects/genericaliasobject.c index acbb01cfef..dbe5d89b73 100644 --- a/contrib/tools/python3/src/Objects/genericaliasobject.c +++ b/contrib/tools/python3/src/Objects/genericaliasobject.c @@ -2,6 +2,7 @@ #include "Python.h" #include "pycore_object.h" +#include "pycore_unionobject.h" // _Py_union_type_or, _PyGenericAlias_Check #include "structmember.h" // PyMemberDef typedef struct { @@ -24,7 +25,7 @@ ga_dealloc(PyObject *self) Py_XDECREF(alias->origin); Py_XDECREF(alias->args); Py_XDECREF(alias->parameters); - self->ob_type->tp_free(self); + Py_TYPE(self)->tp_free(self); } static int @@ -197,8 +198,8 @@ tuple_add(PyObject *self, Py_ssize_t len, PyObject *item) return 0; } -static PyObject * -make_parameters(PyObject *args) +PyObject * +_Py_make_parameters(PyObject *args) { Py_ssize_t nargs = PyTuple_GET_SIZE(args); Py_ssize_t len = nargs; @@ -293,18 +294,10 @@ subs_tvars(PyObject *obj, PyObject *params, PyObject **argitems) return obj; } -static PyObject * -ga_getitem(PyObject *self, PyObject *item) +PyObject * +_Py_subs_parameters(PyObject *self, PyObject *args, PyObject *parameters, PyObject *item) { - gaobject *alias = (gaobject *)self; - // do a lookup for __parameters__ so it gets populated (if not already) - if (alias->parameters == NULL) { - alias->parameters = make_parameters(alias->args); - if (alias->parameters == NULL) { - return NULL; - } - } - Py_ssize_t nparams = PyTuple_GET_SIZE(alias->parameters); + Py_ssize_t nparams = PyTuple_GET_SIZE(parameters); if (nparams == 0) { return PyErr_Format(PyExc_TypeError, "There are no type variables left in %R", @@ -319,32 +312,32 @@ ga_getitem(PyObject *self, PyObject *item) nitems > nparams ? "many" : "few", self); } - /* Replace all type variables (specified by alias->parameters) + /* Replace all type variables (specified by parameters) with corresponding values specified by argitems. t = list[T]; t[int] -> newargs = [int] t = dict[str, T]; t[int] -> newargs = [str, int] t = dict[T, list[S]]; t[str, int] -> newargs = [str, list[int]] */ - Py_ssize_t nargs = PyTuple_GET_SIZE(alias->args); + Py_ssize_t nargs = PyTuple_GET_SIZE(args); PyObject *newargs = PyTuple_New(nargs); if (newargs == NULL) { return NULL; } for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { - PyObject *arg = PyTuple_GET_ITEM(alias->args, iarg); + PyObject *arg = PyTuple_GET_ITEM(args, iarg); int typevar = is_typevar(arg); if (typevar < 0) { Py_DECREF(newargs); return NULL; } if (typevar) { - Py_ssize_t iparam = tuple_index(alias->parameters, nparams, arg); + Py_ssize_t iparam = tuple_index(parameters, nparams, arg); assert(iparam >= 0); arg = argitems[iparam]; Py_INCREF(arg); } else { - arg = subs_tvars(arg, alias->parameters, argitems); + arg = subs_tvars(arg, parameters, argitems); if (arg == NULL) { Py_DECREF(newargs); return NULL; @@ -353,6 +346,26 @@ ga_getitem(PyObject *self, PyObject *item) PyTuple_SET_ITEM(newargs, iarg, arg); } + return newargs; +} + +static PyObject * +ga_getitem(PyObject *self, PyObject *item) +{ + gaobject *alias = (gaobject *)self; + // Populate __parameters__ if needed. + if (alias->parameters == NULL) { + alias->parameters = _Py_make_parameters(alias->args); + if (alias->parameters == NULL) { + return NULL; + } + } + + PyObject *newargs = _Py_subs_parameters(self, alias->args, alias->parameters, item); + if (newargs == NULL) { + return NULL; + } + PyObject *res = Py_GenericAlias(alias->origin, newargs); Py_DECREF(newargs); @@ -430,8 +443,7 @@ ga_getattro(PyObject *self, PyObject *name) static PyObject * ga_richcompare(PyObject *a, PyObject *b, int op) { - if (!PyObject_TypeCheck(a, &Py_GenericAliasType) || - !PyObject_TypeCheck(b, &Py_GenericAliasType) || + if (!_PyGenericAlias_Check(b) || (op != Py_EQ && op != Py_NE)) { Py_RETURN_NOTIMPLEMENTED; @@ -551,7 +563,7 @@ ga_parameters(PyObject *self, void *unused) { gaobject *alias = (gaobject *)self; if (alias->parameters == NULL) { - alias->parameters = make_parameters(alias->args); + alias->parameters = _Py_make_parameters(alias->args); if (alias->parameters == NULL) { return NULL; } @@ -610,6 +622,10 @@ ga_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)self; } +static PyNumberMethods ga_as_number = { + .nb_or = _Py_union_type_or, // Add __or__ function +}; + // TODO: // - argument clinic? // - __doc__? @@ -623,6 +639,7 @@ PyTypeObject Py_GenericAliasType = { .tp_basicsize = sizeof(gaobject), .tp_dealloc = ga_dealloc, .tp_repr = ga_repr, + .tp_as_number = &ga_as_number, // allow X | Y of GenericAlias objs .tp_as_mapping = &ga_as_mapping, .tp_hash = ga_hash, .tp_call = ga_call, diff --git a/contrib/tools/python3/src/Objects/genobject.c b/contrib/tools/python3/src/Objects/genobject.c index 5ba4de82ea..33fc4a5924 100644 --- a/contrib/tools/python3/src/Objects/genobject.c +++ b/contrib/tools/python3/src/Objects/genobject.c @@ -47,7 +47,7 @@ _PyGen_Finalize(PyObject *self) PyObject *res = NULL; PyObject *error_type, *error_value, *error_traceback; - if (gen->gi_frame == NULL || gen->gi_frame->f_stacktop == NULL) { + if (gen->gi_frame == NULL || _PyFrameHasCompleted(gen->gi_frame)) { /* Generator isn't paused, so no need to close */ return; } @@ -136,14 +136,29 @@ gen_dealloc(PyGenObject *gen) PyObject_GC_Del(gen); } -static PyObject * -gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) +static PySendResult +gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult, + int exc, int closing) { PyThreadState *tstate = _PyThreadState_GET(); PyFrameObject *f = gen->gi_frame; PyObject *result; - if (gen->gi_running) { + *presult = NULL; + if (f != NULL && f->f_lasti < 0 && arg && arg != Py_None) { + const char *msg = "can't send non-None value to a " + "just-started generator"; + if (PyCoro_CheckExact(gen)) { + msg = NON_INIT_CORO_MSG; + } + else if (PyAsyncGen_CheckExact(gen)) { + msg = "can't send non-None value to a " + "just-started async generator"; + } + PyErr_SetString(PyExc_TypeError, msg); + return PYGEN_ERROR; + } + if (f != NULL && _PyFrame_IsExecuting(f)) { const char *msg = "generator already executing"; if (PyCoro_CheckExact(gen)) { msg = "coroutine already executing"; @@ -152,9 +167,9 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) msg = "async generator already executing"; } PyErr_SetString(PyExc_ValueError, msg); - return NULL; + return PYGEN_ERROR; } - if (f == NULL || f->f_stacktop == NULL) { + if (f == NULL || _PyFrameHasCompleted(f)) { if (PyCoro_CheckExact(gen) && !closing) { /* `gen` is an exhausted coroutine: raise an error, except when called from gen_close(), which should @@ -165,37 +180,21 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) } else if (arg && !exc) { /* `gen` is an exhausted generator: - only set exception if called from send(). */ - if (PyAsyncGen_CheckExact(gen)) { - PyErr_SetNone(PyExc_StopAsyncIteration); - } - else { - PyErr_SetNone(PyExc_StopIteration); - } + only return value if called from send(). */ + *presult = Py_None; + Py_INCREF(*presult); + return PYGEN_RETURN; } - return NULL; + return PYGEN_ERROR; } - if (f->f_lasti == -1) { - if (arg && arg != Py_None) { - const char *msg = "can't send non-None value to a " - "just-started generator"; - if (PyCoro_CheckExact(gen)) { - msg = NON_INIT_CORO_MSG; - } - else if (PyAsyncGen_CheckExact(gen)) { - msg = "can't send non-None value to a " - "just-started async generator"; - } - PyErr_SetString(PyExc_TypeError, msg); - return NULL; - } - } else { - /* Push arg onto the frame's value stack */ - result = arg ? arg : Py_None; - Py_INCREF(result); - *(f->f_stacktop++) = result; - } + assert(_PyFrame_IsRunnable(f)); + assert(f->f_lasti >= 0 || ((unsigned char *)PyBytes_AS_STRING(f->f_code->co_code))[0] == GEN_START); + /* Push arg onto the frame's value stack */ + result = arg ? arg : Py_None; + Py_INCREF(result); + gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth] = result; + gen->gi_frame->f_stackdepth++; /* Generators always return to their most recent caller, not * necessarily their creator. */ @@ -203,7 +202,6 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) assert(f->f_back == NULL); f->f_back = tstate->frame; - gen->gi_running = 1; gen->gi_exc_state.previous_item = tstate->exc_info; tstate->exc_info = &gen->gi_exc_state; @@ -215,7 +213,6 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) result = _PyEval_EvalFrame(tstate, f, exc); tstate->exc_info = gen->gi_exc_state.previous_item; gen->gi_exc_state.previous_item = NULL; - gen->gi_running = 0; /* Don't keep the reference to f_back any longer than necessary. It * may keep a chain of frames alive or it could create a reference @@ -225,53 +222,73 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) /* If the generator just returned (as opposed to yielding), signal * that the generator is exhausted. */ - if (result && f->f_stacktop == NULL) { - if (result == Py_None) { - /* Delay exception instantiation if we can */ - if (PyAsyncGen_CheckExact(gen)) { - PyErr_SetNone(PyExc_StopAsyncIteration); - } - else { - PyErr_SetNone(PyExc_StopIteration); - } + if (result) { + if (!_PyFrameHasCompleted(f)) { + *presult = result; + return PYGEN_NEXT; } - else { - /* Async generators cannot return anything but None */ - assert(!PyAsyncGen_CheckExact(gen)); - _PyGen_SetStopIterationValue(result); + assert(result == Py_None || !PyAsyncGen_CheckExact(gen)); + if (result == Py_None && !PyAsyncGen_CheckExact(gen) && !arg) { + /* Return NULL if called by gen_iternext() */ + Py_CLEAR(result); } - Py_CLEAR(result); } - else if (!result && PyErr_ExceptionMatches(PyExc_StopIteration)) { - const char *msg = "generator raised StopIteration"; - if (PyCoro_CheckExact(gen)) { - msg = "coroutine raised StopIteration"; + else { + if (PyErr_ExceptionMatches(PyExc_StopIteration)) { + const char *msg = "generator raised StopIteration"; + if (PyCoro_CheckExact(gen)) { + msg = "coroutine raised StopIteration"; + } + else if (PyAsyncGen_CheckExact(gen)) { + msg = "async generator raised StopIteration"; + } + _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } - else if (PyAsyncGen_CheckExact(gen)) { - msg = "async generator raised StopIteration"; + else if (PyAsyncGen_CheckExact(gen) && + PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) + { + /* code in `gen` raised a StopAsyncIteration error: + raise a RuntimeError. + */ + const char *msg = "async generator raised StopAsyncIteration"; + _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } - _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); - - } - else if (!result && PyAsyncGen_CheckExact(gen) && - PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) - { - /* code in `gen` raised a StopAsyncIteration error: - raise a RuntimeError. - */ - const char *msg = "async generator raised StopAsyncIteration"; - _PyErr_FormatFromCause(PyExc_RuntimeError, "%s", msg); } - if (!result || f->f_stacktop == NULL) { - /* generator can't be rerun, so release the frame */ - /* first clean reference cycle through stored exception traceback */ - _PyErr_ClearExcState(&gen->gi_exc_state); - gen->gi_frame->f_gen = NULL; - gen->gi_frame = NULL; - Py_DECREF(f); - } + /* generator can't be rerun, so release the frame */ + /* first clean reference cycle through stored exception traceback */ + _PyErr_ClearExcState(&gen->gi_exc_state); + gen->gi_frame->f_gen = NULL; + gen->gi_frame = NULL; + Py_DECREF(f); + + *presult = result; + return result ? PYGEN_RETURN : PYGEN_ERROR; +} +static PySendResult +PyGen_am_send(PyGenObject *gen, PyObject *arg, PyObject **result) +{ + return gen_send_ex2(gen, arg, result, 0, 0); +} + +static PyObject * +gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) +{ + PyObject *result; + if (gen_send_ex2(gen, arg, &result, exc, closing) == PYGEN_RETURN) { + if (PyAsyncGen_CheckExact(gen)) { + assert(result == Py_None); + PyErr_SetNone(PyExc_StopAsyncIteration); + } + else if (result == Py_None) { + PyErr_SetNone(PyExc_StopIteration); + } + else { + _PyGen_SetStopIterationValue(result); + } + Py_CLEAR(result); + } return result; } @@ -279,8 +296,8 @@ PyDoc_STRVAR(send_doc, "send(arg) -> send 'arg' into generator,\n\ return next yielded value or raise StopIteration."); -PyObject * -_PyGen_Send(PyGenObject *gen, PyObject *arg) +static PyObject * +gen_send(PyGenObject *gen, PyObject *arg) { return gen_send_ex(gen, arg, 0, 0); } @@ -326,7 +343,7 @@ _PyGen_yf(PyGenObject *gen) PyObject *yf = NULL; PyFrameObject *f = gen->gi_frame; - if (f && f->f_stacktop) { + if (f) { PyObject *bytecode = f->f_code->co_code; unsigned char *code = (unsigned char *)PyBytes_AS_STRING(bytecode); @@ -338,9 +355,10 @@ _PyGen_yf(PyGenObject *gen) return NULL; } - if (code[f->f_lasti + sizeof(_Py_CODEUNIT)] != YIELD_FROM) + if (code[(f->f_lasti+1)*sizeof(_Py_CODEUNIT)] != YIELD_FROM) return NULL; - yf = f->f_stacktop[-1]; + assert(f->f_stackdepth > 0); + yf = f->f_valuestack[f->f_stackdepth-1]; Py_INCREF(yf); } @@ -355,9 +373,10 @@ gen_close(PyGenObject *gen, PyObject *args) int err = 0; if (yf) { - gen->gi_running = 1; + PyFrameState state = gen->gi_frame->f_state; + gen->gi_frame->f_state = FRAME_EXECUTING; err = gen_close_iter(yf); - gen->gi_running = 0; + gen->gi_frame->f_state = state; Py_DECREF(yf); } if (err == 0) @@ -404,9 +423,10 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, We have to allow some awaits to work it through, hence the `close_on_genexit` parameter here. */ - gen->gi_running = 1; + PyFrameState state = gen->gi_frame->f_state; + gen->gi_frame->f_state = FRAME_EXECUTING; err = gen_close_iter(yf); - gen->gi_running = 0; + gen->gi_frame->f_state = state; Py_DECREF(yf); if (err < 0) return gen_send_ex(gen, Py_None, 1, 0); @@ -417,7 +437,6 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, PyThreadState *tstate = _PyThreadState_GET(); PyFrameObject *f = tstate->frame; - gen->gi_running = 1; /* Since we are fast-tracking things by skipping the eval loop, we need to update the current frame so the stack trace will be reported correctly to the user. */ @@ -426,10 +445,12 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, tstate->frame = gen->gi_frame; /* Close the generator that we are currently iterating with 'yield from' or awaiting on with 'await'. */ + PyFrameState state = gen->gi_frame->f_state; + gen->gi_frame->f_state = FRAME_EXECUTING; ret = _gen_throw((PyGenObject *)yf, close_on_genexit, typ, val, tb); + gen->gi_frame->f_state = state; tstate->frame = f; - gen->gi_running = 0; } else { /* `yf` is an iterator or a coroutine-like object. */ PyObject *meth; @@ -441,23 +462,26 @@ _gen_throw(PyGenObject *gen, int close_on_genexit, Py_DECREF(yf); goto throw_here; } - gen->gi_running = 1; + PyFrameState state = gen->gi_frame->f_state; + gen->gi_frame->f_state = FRAME_EXECUTING; ret = PyObject_CallFunctionObjArgs(meth, typ, val, tb, NULL); - gen->gi_running = 0; + gen->gi_frame->f_state = state; Py_DECREF(meth); } Py_DECREF(yf); if (!ret) { PyObject *val; /* Pop subiterator from stack */ - ret = *(--gen->gi_frame->f_stacktop); + assert(gen->gi_frame->f_stackdepth > 0); + gen->gi_frame->f_stackdepth--; + ret = gen->gi_frame->f_valuestack[gen->gi_frame->f_stackdepth]; assert(ret == yf); Py_DECREF(ret); /* Termination repetition of YIELD_FROM */ assert(gen->gi_frame->f_lasti >= 0); - gen->gi_frame->f_lasti += sizeof(_Py_CODEUNIT); + gen->gi_frame->f_lasti += 1; if (_PyGen_FetchStopIterationValue(&val) == 0) { - ret = gen_send_ex(gen, val, 0, 0); + ret = gen_send(gen, val); Py_DECREF(val); } else { ret = gen_send_ex(gen, Py_None, 1, 0); @@ -543,7 +567,15 @@ gen_throw(PyGenObject *gen, PyObject *args) static PyObject * gen_iternext(PyGenObject *gen) { - return gen_send_ex(gen, NULL, 0, 0); + PyObject *result; + assert(PyGen_CheckExact(gen) || PyCoro_CheckExact(gen)); + if (gen_send_ex2(gen, NULL, &result, 0, 0) == PYGEN_RETURN) { + if (result != Py_None) { + _PyGen_SetStopIterationValue(result); + } + Py_CLEAR(result); + } + return result; } /* @@ -700,6 +732,16 @@ gen_getyieldfrom(PyGenObject *gen, void *Py_UNUSED(ignored)) return yf; } + +static PyObject * +gen_getrunning(PyGenObject *gen, void *Py_UNUSED(ignored)) +{ + if (gen->gi_frame == NULL) { + Py_RETURN_FALSE; + } + return PyBool_FromLong(_PyFrame_IsExecuting(gen->gi_frame)); +} + static PyGetSetDef gen_getsetlist[] = { {"__name__", (getter)gen_get_name, (setter)gen_set_name, PyDoc_STR("name of the generator")}, @@ -707,23 +749,31 @@ static PyGetSetDef gen_getsetlist[] = { PyDoc_STR("qualified name of the generator")}, {"gi_yieldfrom", (getter)gen_getyieldfrom, NULL, PyDoc_STR("object being iterated by yield from, or None")}, + {"gi_running", (getter)gen_getrunning, NULL, NULL}, {NULL} /* Sentinel */ }; static PyMemberDef gen_memberlist[] = { - {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY|READ_RESTRICTED}, - {"gi_running", T_BOOL, offsetof(PyGenObject, gi_running), READONLY}, - {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY|READ_RESTRICTED}, + {"gi_frame", T_OBJECT, offsetof(PyGenObject, gi_frame), READONLY|PY_AUDIT_READ}, + {"gi_code", T_OBJECT, offsetof(PyGenObject, gi_code), READONLY|PY_AUDIT_READ}, {NULL} /* Sentinel */ }; static PyMethodDef gen_methods[] = { - {"send",(PyCFunction)_PyGen_Send, METH_O, send_doc}, + {"send",(PyCFunction)gen_send, METH_O, send_doc}, {"throw",(PyCFunction)gen_throw, METH_VARARGS, throw_doc}, {"close",(PyCFunction)gen_close, METH_NOARGS, close_doc}, {NULL, NULL} /* Sentinel */ }; +static PyAsyncMethods gen_as_async = { + 0, /* am_await */ + 0, /* am_aiter */ + 0, /* am_anext */ + (sendfunc)PyGen_am_send, /* am_send */ +}; + + PyTypeObject PyGen_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "generator", /* tp_name */ @@ -734,7 +784,7 @@ PyTypeObject PyGen_Type = { 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ - 0, /* tp_as_async */ + &gen_as_async, /* tp_as_async */ (reprfunc)gen_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ @@ -790,7 +840,6 @@ gen_new_with_qualname(PyTypeObject *type, PyFrameObject *f, f->f_gen = (PyObject *) gen; Py_INCREF(f->f_code); gen->gi_code = (PyObject *)(f->f_code); - gen->gi_running = 0; gen->gi_weakreflist = NULL; gen->gi_exc_state.exc_type = NULL; gen->gi_exc_state.exc_value = NULL; @@ -920,6 +969,15 @@ coro_get_cr_await(PyCoroObject *coro, void *Py_UNUSED(ignored)) return yf; } +static PyObject * +cr_getrunning(PyCoroObject *coro, void *Py_UNUSED(ignored)) +{ + if (coro->cr_frame == NULL) { + Py_RETURN_FALSE; + } + return PyBool_FromLong(_PyFrame_IsExecuting(coro->cr_frame)); +} + static PyGetSetDef coro_getsetlist[] = { {"__name__", (getter)gen_get_name, (setter)gen_set_name, PyDoc_STR("name of the coroutine")}, @@ -927,13 +985,13 @@ static PyGetSetDef coro_getsetlist[] = { PyDoc_STR("qualified name of the coroutine")}, {"cr_await", (getter)coro_get_cr_await, NULL, PyDoc_STR("object being awaited on, or None")}, + {"cr_running", (getter)cr_getrunning, NULL, NULL}, {NULL} /* Sentinel */ }; static PyMemberDef coro_memberlist[] = { - {"cr_frame", T_OBJECT, offsetof(PyCoroObject, cr_frame), READONLY|READ_RESTRICTED}, - {"cr_running", T_BOOL, offsetof(PyCoroObject, cr_running), READONLY}, - {"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY|READ_RESTRICTED}, + {"cr_frame", T_OBJECT, offsetof(PyCoroObject, cr_frame), READONLY|PY_AUDIT_READ}, + {"cr_code", T_OBJECT, offsetof(PyCoroObject, cr_code), READONLY|PY_AUDIT_READ}, {"cr_origin", T_OBJECT, offsetof(PyCoroObject, cr_origin), READONLY}, {NULL} /* Sentinel */ }; @@ -950,7 +1008,7 @@ PyDoc_STRVAR(coro_close_doc, "close() -> raise GeneratorExit inside coroutine."); static PyMethodDef coro_methods[] = { - {"send",(PyCFunction)_PyGen_Send, METH_O, coro_send_doc}, + {"send",(PyCFunction)gen_send, METH_O, coro_send_doc}, {"throw",(PyCFunction)gen_throw, METH_VARARGS, coro_throw_doc}, {"close",(PyCFunction)gen_close, METH_NOARGS, coro_close_doc}, {NULL, NULL} /* Sentinel */ @@ -959,7 +1017,8 @@ static PyMethodDef coro_methods[] = { static PyAsyncMethods coro_as_async = { (unaryfunc)coro_await, /* am_await */ 0, /* am_aiter */ - 0 /* am_anext */ + 0, /* am_anext */ + (sendfunc)PyGen_am_send, /* am_send */ }; PyTypeObject PyCoro_Type = { @@ -1025,13 +1084,13 @@ coro_wrapper_dealloc(PyCoroWrapper *cw) static PyObject * coro_wrapper_iternext(PyCoroWrapper *cw) { - return gen_send_ex((PyGenObject *)cw->cw_coroutine, NULL, 0, 0); + return gen_iternext((PyGenObject *)cw->cw_coroutine); } static PyObject * coro_wrapper_send(PyCoroWrapper *cw, PyObject *arg) { - return gen_send_ex((PyGenObject *)cw->cw_coroutine, arg, 0, 0); + return gen_send((PyGenObject *)cw->cw_coroutine, arg); } static PyObject * @@ -1171,7 +1230,7 @@ typedef enum { } AwaitableState; -typedef struct { +typedef struct PyAsyncGenASend { PyObject_HEAD PyAsyncGenObject *ags_gen; @@ -1183,7 +1242,7 @@ typedef struct { } PyAsyncGenASend; -typedef struct { +typedef struct PyAsyncGenAThrow { PyObject_HEAD PyAsyncGenObject *agt_gen; @@ -1195,28 +1254,12 @@ typedef struct { } PyAsyncGenAThrow; -typedef struct { +typedef struct _PyAsyncGenWrappedValue { PyObject_HEAD PyObject *agw_val; } _PyAsyncGenWrappedValue; -#ifndef _PyAsyncGen_MAXFREELIST -#define _PyAsyncGen_MAXFREELIST 80 -#endif - -/* Freelists boost performance 6-10%; they also reduce memory - fragmentation, as _PyAsyncGenWrappedValue and PyAsyncGenASend - are short-living objects that are instantiated for every - __anext__ call. -*/ - -static _PyAsyncGenWrappedValue *ag_value_freelist[_PyAsyncGen_MAXFREELIST]; -static int ag_value_freelist_free = 0; - -static PyAsyncGenASend *ag_asend_freelist[_PyAsyncGen_MAXFREELIST]; -static int ag_asend_freelist_free = 0; - #define _PyAsyncGenWrappedValue_CheckExact(o) \ Py_IS_TYPE(o, &_PyAsyncGenWrappedValue_Type) @@ -1328,12 +1371,10 @@ static PyGetSetDef async_gen_getsetlist[] = { }; static PyMemberDef async_gen_memberlist[] = { - {"ag_frame", T_OBJECT, offsetof(PyAsyncGenObject, ag_frame), - READONLY|READ_RESTRICTED}, + {"ag_frame", T_OBJECT, offsetof(PyAsyncGenObject, ag_frame), READONLY|PY_AUDIT_READ}, {"ag_running", T_BOOL, offsetof(PyAsyncGenObject, ag_running_async), READONLY}, - {"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), - READONLY|READ_RESTRICTED}, + {"ag_code", T_OBJECT, offsetof(PyAsyncGenObject, ag_code), READONLY|PY_AUDIT_READ}, {NULL} /* Sentinel */ }; @@ -1359,7 +1400,8 @@ static PyMethodDef async_gen_methods[] = { static PyAsyncMethods async_gen_as_async = { 0, /* am_await */ PyObject_SelfIter, /* am_aiter */ - (unaryfunc)async_gen_anext /* am_anext */ + (unaryfunc)async_gen_anext, /* am_anext */ + (sendfunc)PyGen_am_send, /* am_send */ }; @@ -1416,6 +1458,14 @@ PyTypeObject PyAsyncGen_Type = { }; +static struct _Py_async_gen_state * +get_async_gen_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->async_gen; +} + + PyObject * PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) { @@ -1434,27 +1484,34 @@ PyAsyncGen_New(PyFrameObject *f, PyObject *name, PyObject *qualname) void -_PyAsyncGen_ClearFreeLists(void) +_PyAsyncGen_ClearFreeLists(PyInterpreterState *interp) { - while (ag_value_freelist_free) { + struct _Py_async_gen_state *state = &interp->async_gen; + + while (state->value_numfree) { _PyAsyncGenWrappedValue *o; - o = ag_value_freelist[--ag_value_freelist_free]; + o = state->value_freelist[--state->value_numfree]; assert(_PyAsyncGenWrappedValue_CheckExact(o)); PyObject_GC_Del(o); } - while (ag_asend_freelist_free) { + while (state->asend_numfree) { PyAsyncGenASend *o; - o = ag_asend_freelist[--ag_asend_freelist_free]; + o = state->asend_freelist[--state->asend_numfree]; assert(Py_IS_TYPE(o, &_PyAsyncGenASend_Type)); PyObject_GC_Del(o); } } void -_PyAsyncGen_Fini(void) +_PyAsyncGen_Fini(PyInterpreterState *interp) { - _PyAsyncGen_ClearFreeLists(); + _PyAsyncGen_ClearFreeLists(interp); +#ifdef Py_DEBUG + struct _Py_async_gen_state *state = &interp->async_gen; + state->value_numfree = -1; + state->asend_numfree = -1; +#endif } @@ -1497,10 +1554,16 @@ async_gen_asend_dealloc(PyAsyncGenASend *o) _PyObject_GC_UNTRACK((PyObject *)o); Py_CLEAR(o->ags_gen); Py_CLEAR(o->ags_sendval); - if (ag_asend_freelist_free < _PyAsyncGen_MAXFREELIST) { + struct _Py_async_gen_state *state = get_async_gen_state(); +#ifdef Py_DEBUG + // async_gen_asend_dealloc() must not be called after _PyAsyncGen_Fini() + assert(state->asend_numfree != -1); +#endif + if (state->asend_numfree < _PyAsyncGen_MAXFREELIST) { assert(PyAsyncGenASend_CheckExact(o)); - ag_asend_freelist[ag_asend_freelist_free++] = o; - } else { + state->asend_freelist[state->asend_numfree++] = o; + } + else { PyObject_GC_Del(o); } } @@ -1541,7 +1604,7 @@ async_gen_asend_send(PyAsyncGenASend *o, PyObject *arg) } o->ags_gen->ag_running_async = 1; - result = gen_send_ex((PyGenObject*)o->ags_gen, arg, 0, 0); + result = gen_send((PyGenObject*)o->ags_gen, arg); result = async_gen_unwrap_value(o->ags_gen, result); if (result == NULL) { @@ -1601,7 +1664,8 @@ static PyMethodDef async_gen_asend_methods[] = { static PyAsyncMethods async_gen_asend_as_async = { PyObject_SelfIter, /* am_await */ 0, /* am_aiter */ - 0 /* am_anext */ + 0, /* am_anext */ + 0, /* am_send */ }; @@ -1652,11 +1716,17 @@ static PyObject * async_gen_asend_new(PyAsyncGenObject *gen, PyObject *sendval) { PyAsyncGenASend *o; - if (ag_asend_freelist_free) { - ag_asend_freelist_free--; - o = ag_asend_freelist[ag_asend_freelist_free]; + struct _Py_async_gen_state *state = get_async_gen_state(); +#ifdef Py_DEBUG + // async_gen_asend_new() must not be called after _PyAsyncGen_Fini() + assert(state->asend_numfree != -1); +#endif + if (state->asend_numfree) { + state->asend_numfree--; + o = state->asend_freelist[state->asend_numfree]; _Py_NewReference((PyObject *)o); - } else { + } + else { o = PyObject_GC_New(PyAsyncGenASend, &_PyAsyncGenASend_Type); if (o == NULL) { return NULL; @@ -1684,10 +1754,16 @@ async_gen_wrapped_val_dealloc(_PyAsyncGenWrappedValue *o) { _PyObject_GC_UNTRACK((PyObject *)o); Py_CLEAR(o->agw_val); - if (ag_value_freelist_free < _PyAsyncGen_MAXFREELIST) { + struct _Py_async_gen_state *state = get_async_gen_state(); +#ifdef Py_DEBUG + // async_gen_wrapped_val_dealloc() must not be called after _PyAsyncGen_Fini() + assert(state->value_numfree != -1); +#endif + if (state->value_numfree < _PyAsyncGen_MAXFREELIST) { assert(_PyAsyncGenWrappedValue_CheckExact(o)); - ag_value_freelist[ag_value_freelist_free++] = o; - } else { + state->value_freelist[state->value_numfree++] = o; + } + else { PyObject_GC_Del(o); } } @@ -1751,12 +1827,18 @@ _PyAsyncGenValueWrapperNew(PyObject *val) _PyAsyncGenWrappedValue *o; assert(val); - if (ag_value_freelist_free) { - ag_value_freelist_free--; - o = ag_value_freelist[ag_value_freelist_free]; + struct _Py_async_gen_state *state = get_async_gen_state(); +#ifdef Py_DEBUG + // _PyAsyncGenValueWrapperNew() must not be called after _PyAsyncGen_Fini() + assert(state->value_numfree != -1); +#endif + if (state->value_numfree) { + state->value_numfree--; + o = state->value_freelist[state->value_numfree]; assert(_PyAsyncGenWrappedValue_CheckExact(o)); _Py_NewReference((PyObject*)o); - } else { + } + else { o = PyObject_GC_New(_PyAsyncGenWrappedValue, &_PyAsyncGenWrappedValue_Type); if (o == NULL) { @@ -1806,7 +1888,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) return NULL; } - if (f == NULL || f->f_stacktop == NULL) { + if (f == NULL || _PyFrameHasCompleted(f)) { o->agt_state = AWAITABLE_STATE_CLOSED; PyErr_SetNone(PyExc_StopIteration); return NULL; @@ -1879,7 +1961,7 @@ async_gen_athrow_send(PyAsyncGenAThrow *o, PyObject *arg) assert(o->agt_state == AWAITABLE_STATE_ITER); - retval = gen_send_ex((PyGenObject *)gen, arg, 0, 0); + retval = gen_send((PyGenObject *)gen, arg); if (o->agt_args) { return async_gen_unwrap_value(o->agt_gen, retval); } else { @@ -1991,7 +2073,8 @@ static PyMethodDef async_gen_athrow_methods[] = { static PyAsyncMethods async_gen_athrow_as_async = { PyObject_SelfIter, /* am_await */ 0, /* am_aiter */ - 0 /* am_anext */ + 0, /* am_anext */ + 0, /* am_send */ }; diff --git a/contrib/tools/python3/src/Objects/interpreteridobject.c b/contrib/tools/python3/src/Objects/interpreteridobject.c index 39bde97269..46239100dc 100644 --- a/contrib/tools/python3/src/Objects/interpreteridobject.c +++ b/contrib/tools/python3/src/Objects/interpreteridobject.c @@ -24,15 +24,21 @@ newinterpid(PyTypeObject *cls, int64_t id, int force) } } + if (interp != NULL) { + if (_PyInterpreterState_IDIncref(interp) < 0) { + return NULL; + } + } + interpid *self = PyObject_New(interpid, cls); if (self == NULL) { + if (interp != NULL) { + _PyInterpreterState_IDDecref(interp); + } return NULL; } self->id = id; - if (interp != NULL) { - _PyInterpreterState_IDIncref(interp); - } return self; } diff --git a/contrib/tools/python3/src/Objects/iterobject.c b/contrib/tools/python3/src/Objects/iterobject.c index 6cac41ad53..e493e41131 100644 --- a/contrib/tools/python3/src/Objects/iterobject.c +++ b/contrib/tools/python3/src/Objects/iterobject.c @@ -157,7 +157,7 @@ PyTypeObject PySeqIter_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)iter_traverse, /* tp_traverse */ 0, /* tp_clear */ @@ -276,7 +276,7 @@ PyTypeObject PyCallIter_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)calliter_traverse, /* tp_traverse */ 0, /* tp_clear */ @@ -288,3 +288,214 @@ PyTypeObject PyCallIter_Type = { }; +/* -------------------------------------- */ + +typedef struct { + PyObject_HEAD + PyObject *wrapped; + PyObject *default_value; +} anextawaitableobject; + +static void +anextawaitable_dealloc(anextawaitableobject *obj) +{ + _PyObject_GC_UNTRACK(obj); + Py_XDECREF(obj->wrapped); + Py_XDECREF(obj->default_value); + PyObject_GC_Del(obj); +} + +static int +anextawaitable_traverse(anextawaitableobject *obj, visitproc visit, void *arg) +{ + Py_VISIT(obj->wrapped); + Py_VISIT(obj->default_value); + return 0; +} + +static PyObject * +anextawaitable_getiter(anextawaitableobject *obj) +{ + assert(obj->wrapped != NULL); + PyObject *awaitable = _PyCoro_GetAwaitableIter(obj->wrapped); + if (awaitable == NULL) { + return NULL; + } + if (Py_TYPE(awaitable)->tp_iternext == NULL) { + /* _PyCoro_GetAwaitableIter returns a Coroutine, a Generator, + * or an iterator. Of these, only coroutines lack tp_iternext. + */ + assert(PyCoro_CheckExact(awaitable)); + unaryfunc getter = Py_TYPE(awaitable)->tp_as_async->am_await; + PyObject *new_awaitable = getter(awaitable); + if (new_awaitable == NULL) { + Py_DECREF(awaitable); + return NULL; + } + Py_SETREF(awaitable, new_awaitable); + if (!PyIter_Check(awaitable)) { + PyErr_SetString(PyExc_TypeError, + "__await__ returned a non-iterable"); + Py_DECREF(awaitable); + return NULL; + } + } + return awaitable; +} + +static PyObject * +anextawaitable_iternext(anextawaitableobject *obj) +{ + /* Consider the following class: + * + * class A: + * async def __anext__(self): + * ... + * a = A() + * + * Then `await anext(a)` should call + * a.__anext__().__await__().__next__() + * + * On the other hand, given + * + * async def agen(): + * yield 1 + * yield 2 + * gen = agen() + * + * Then `await anext(gen)` can just call + * gen.__anext__().__next__() + */ + PyObject *awaitable = anextawaitable_getiter(obj); + if (awaitable == NULL) { + return NULL; + } + PyObject *result = (*Py_TYPE(awaitable)->tp_iternext)(awaitable); + Py_DECREF(awaitable); + if (result != NULL) { + return result; + } + if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) { + _PyGen_SetStopIterationValue(obj->default_value); + } + return NULL; +} + + +static PyObject * +anextawaitable_proxy(anextawaitableobject *obj, char *meth, PyObject *arg) { + PyObject *awaitable = anextawaitable_getiter(obj); + if (awaitable == NULL) { + return NULL; + } + PyObject *ret = PyObject_CallMethod(awaitable, meth, "O", arg); + Py_DECREF(awaitable); + if (ret != NULL) { + return ret; + } + if (PyErr_ExceptionMatches(PyExc_StopAsyncIteration)) { + /* `anextawaitableobject` is only used by `anext()` when + * a default value is provided. So when we have a StopAsyncIteration + * exception we replace it with a `StopIteration(default)`, as if + * it was the return value of `__anext__()` coroutine. + */ + _PyGen_SetStopIterationValue(obj->default_value); + } + return NULL; +} + + +static PyObject * +anextawaitable_send(anextawaitableobject *obj, PyObject *arg) { + return anextawaitable_proxy(obj, "send", arg); +} + + +static PyObject * +anextawaitable_throw(anextawaitableobject *obj, PyObject *arg) { + return anextawaitable_proxy(obj, "throw", arg); +} + + +static PyObject * +anextawaitable_close(anextawaitableobject *obj, PyObject *arg) { + return anextawaitable_proxy(obj, "close", arg); +} + + +PyDoc_STRVAR(send_doc, +"send(arg) -> send 'arg' into the wrapped iterator,\n\ +return next yielded value or raise StopIteration."); + + +PyDoc_STRVAR(throw_doc, +"throw(typ[,val[,tb]]) -> raise exception in the wrapped iterator,\n\ +return next yielded value or raise StopIteration."); + + +PyDoc_STRVAR(close_doc, +"close() -> raise GeneratorExit inside generator."); + + +static PyMethodDef anextawaitable_methods[] = { + {"send",(PyCFunction)anextawaitable_send, METH_O, send_doc}, + {"throw",(PyCFunction)anextawaitable_throw, METH_VARARGS, throw_doc}, + {"close",(PyCFunction)anextawaitable_close, METH_VARARGS, close_doc}, + {NULL, NULL} /* Sentinel */ +}; + + +static PyAsyncMethods anextawaitable_as_async = { + PyObject_SelfIter, /* am_await */ + 0, /* am_aiter */ + 0, /* am_anext */ + 0, /* am_send */ +}; + +PyTypeObject _PyAnextAwaitable_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "anext_awaitable", /* tp_name */ + sizeof(anextawaitableobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)anextawaitable_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + &anextawaitable_as_async, /* 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 */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ + 0, /* tp_doc */ + (traverseproc)anextawaitable_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (unaryfunc)anextawaitable_iternext, /* tp_iternext */ + anextawaitable_methods, /* tp_methods */ +}; + +PyObject * +PyAnextAwaitable_New(PyObject *awaitable, PyObject *default_value) +{ + anextawaitableobject *anext = PyObject_GC_New( + anextawaitableobject, &_PyAnextAwaitable_Type); + if (anext == NULL) { + return NULL; + } + Py_INCREF(awaitable); + anext->wrapped = awaitable; + Py_INCREF(default_value); + anext->default_value = default_value; + _PyObject_GC_TRACK(anext); + return (PyObject *)anext; +} diff --git a/contrib/tools/python3/src/Objects/listobject.c b/contrib/tools/python3/src/Objects/listobject.c index 1e868b43c0..533ee7436d 100644 --- a/contrib/tools/python3/src/Objects/listobject.c +++ b/contrib/tools/python3/src/Objects/listobject.c @@ -1,10 +1,10 @@ /* List object implementation */ #include "Python.h" -#include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_object.h" -#include "pycore_tupleobject.h" -#include "pycore_accu.h" +#include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_interp.h" // PyInterpreterState.list +#include "pycore_object.h" // _PyObject_GC_TRACK() +#include "pycore_tuple.h" // _PyTuple_FromArray() #ifdef STDC_HEADERS #include <stddef.h> @@ -19,6 +19,15 @@ class list "PyListObject *" "&PyList_Type" #include "clinic/listobject.c.h" + +static struct _Py_list_state * +get_list_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->list; +} + + /* Ensure ob_item has room for at least newsize elements, and set * ob_size to newsize. If newsize > ob_size on entry, the content * of the new slots at exit is undefined heap trash; it's the caller's @@ -60,7 +69,7 @@ list_resize(PyListObject *self, Py_ssize_t newsize) * is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t. */ new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3; - /* Do not overallocate if the new size is closer to overalocated size + /* Do not overallocate if the new size is closer to overallocated size * than to the old size. */ if (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize)) @@ -96,59 +105,65 @@ list_preallocate_exact(PyListObject *self, Py_ssize_t size) return 0; } -/* Empty list reuse scheme to save calls to malloc and free */ -#ifndef PyList_MAXFREELIST -# define PyList_MAXFREELIST 80 -#endif - -static PyListObject *free_list[PyList_MAXFREELIST]; -static int numfree = 0; - void -_PyList_ClearFreeList(void) +_PyList_ClearFreeList(PyInterpreterState *interp) { - while (numfree) { - PyListObject *op = free_list[--numfree]; + struct _Py_list_state *state = &interp->list; + while (state->numfree) { + PyListObject *op = state->free_list[--state->numfree]; assert(PyList_CheckExact(op)); PyObject_GC_Del(op); } } void -_PyList_Fini(void) +_PyList_Fini(PyInterpreterState *interp) { - _PyList_ClearFreeList(); + _PyList_ClearFreeList(interp); +#ifdef Py_DEBUG + struct _Py_list_state *state = &interp->list; + state->numfree = -1; +#endif } /* Print summary info about the state of the optimized allocator */ void _PyList_DebugMallocStats(FILE *out) { + struct _Py_list_state *state = get_list_state(); _PyDebugAllocatorStats(out, "free PyListObject", - numfree, sizeof(PyListObject)); + state->numfree, sizeof(PyListObject)); } PyObject * PyList_New(Py_ssize_t size) { - PyListObject *op; - if (size < 0) { PyErr_BadInternalCall(); return NULL; } - if (numfree) { - numfree--; - op = free_list[numfree]; + + struct _Py_list_state *state = get_list_state(); + PyListObject *op; +#ifdef Py_DEBUG + // PyList_New() must not be called after _PyList_Fini() + assert(state->numfree != -1); +#endif + if (state->numfree) { + state->numfree--; + op = state->free_list[state->numfree]; _Py_NewReference((PyObject *)op); - } else { + } + else { op = PyObject_GC_New(PyListObject, &PyList_Type); - if (op == NULL) + if (op == NULL) { return NULL; + } } - if (size <= 0) + if (size <= 0) { op->ob_item = NULL; + } else { op->ob_item = (PyObject **) PyMem_Calloc(size, sizeof(PyObject *)); if (op->ob_item == NULL) { @@ -256,12 +271,8 @@ ins1(PyListObject *self, Py_ssize_t where, PyObject *v) PyErr_BadInternalCall(); return -1; } - if (n == PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "cannot add more objects to list"); - return -1; - } + assert((size_t)n + 1 < PY_SSIZE_T_MAX); if (list_resize(self, n+1) < 0) return -1; @@ -296,12 +307,7 @@ app1(PyListObject *self, PyObject *v) Py_ssize_t n = PyList_GET_SIZE(self); assert (v != NULL); - if (n == PY_SSIZE_T_MAX) { - PyErr_SetString(PyExc_OverflowError, - "cannot add more objects to list"); - return -1; - } - + assert((size_t)n + 1 < PY_SSIZE_T_MAX); if (list_resize(self, n+1) < 0) return -1; @@ -336,12 +342,19 @@ list_dealloc(PyListObject *op) while (--i >= 0) { Py_XDECREF(op->ob_item[i]); } - PyMem_FREE(op->ob_item); + PyMem_Free(op->ob_item); } - if (numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) - free_list[numfree++] = op; - else + struct _Py_list_state *state = get_list_state(); +#ifdef Py_DEBUG + // list_dealloc() must not be called after _PyList_Fini() + assert(state->numfree != -1); +#endif + if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) { + state->free_list[state->numfree++] = op; + } + else { Py_TYPE(op)->tp_free((PyObject *)op); + } Py_TRASHCAN_END } @@ -501,8 +514,7 @@ list_concat(PyListObject *a, PyObject *bb) return NULL; } #define b ((PyListObject *)bb) - if (Py_SIZE(a) > PY_SSIZE_T_MAX - Py_SIZE(b)) - return PyErr_NoMemory(); + assert((size_t)Py_SIZE(a) + (size_t)Py_SIZE(b) < PY_SSIZE_T_MAX); size = Py_SIZE(a) + Py_SIZE(b); if (size == 0) { return PyList_New(0); @@ -587,7 +599,7 @@ _list_clear(PyListObject *a) while (--i >= 0) { Py_XDECREF(item[i]); } - PyMem_FREE(item); + PyMem_Free(item); } /* Never fails; the return value can be ignored. Note that there is no guarantee that the list is actually empty @@ -663,7 +675,7 @@ list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) /* If norig == 0, item might be NULL, in which case we may not memcpy from it. */ if (s) { if (s > sizeof(recycle_on_stack)) { - recycle = (PyObject **)PyMem_MALLOC(s); + recycle = (PyObject **)PyMem_Malloc(s); if (recycle == NULL) { PyErr_NoMemory(); goto Error; @@ -701,7 +713,7 @@ list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v) result = 0; Error: if (recycle != recycle_on_stack) - PyMem_FREE(recycle); + PyMem_Free(recycle); Py_XDECREF(v_as_SF); return result; #undef b @@ -2225,7 +2237,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse) /* Leverage stack space we allocated but won't otherwise use */ keys = &ms.temparray[saved_ob_size+1]; else { - keys = PyMem_MALLOC(sizeof(PyObject *) * saved_ob_size); + keys = PyMem_Malloc(sizeof(PyObject *) * saved_ob_size); if (keys == NULL) { PyErr_NoMemory(); goto keyfunc_fail; @@ -2238,7 +2250,7 @@ list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse) for (i=i-1 ; i>=0 ; i--) Py_DECREF(keys[i]); if (saved_ob_size >= MERGESTATE_TEMP_SIZE/2) - PyMem_FREE(keys); + PyMem_Free(keys); goto keyfunc_fail; } } @@ -2409,7 +2421,7 @@ fail: for (i = 0; i < saved_ob_size; i++) Py_DECREF(keys[i]); if (saved_ob_size >= MERGESTATE_TEMP_SIZE/2) - PyMem_FREE(keys); + PyMem_Free(keys); } if (self->allocated != -1 && result != NULL) { @@ -2437,7 +2449,7 @@ keyfunc_fail: while (--i >= 0) { Py_XDECREF(final_ob_item[i]); } - PyMem_FREE(final_ob_item); + PyMem_Free(final_ob_item); } Py_XINCREF(result); return result; @@ -2903,7 +2915,7 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) } garbage = (PyObject**) - PyMem_MALLOC(slicelength*sizeof(PyObject*)); + PyMem_Malloc(slicelength*sizeof(PyObject*)); if (!garbage) { PyErr_NoMemory(); return -1; @@ -2944,7 +2956,7 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) for (i = 0; i < slicelength; i++) { Py_DECREF(garbage[i]); } - PyMem_FREE(garbage); + PyMem_Free(garbage); return res; } @@ -2985,7 +2997,7 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) } garbage = (PyObject**) - PyMem_MALLOC(slicelength*sizeof(PyObject*)); + PyMem_Malloc(slicelength*sizeof(PyObject*)); if (!garbage) { Py_DECREF(seq); PyErr_NoMemory(); @@ -3006,7 +3018,7 @@ list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) Py_DECREF(garbage[i]); } - PyMem_FREE(garbage); + PyMem_Free(garbage); Py_DECREF(seq); return 0; @@ -3047,7 +3059,8 @@ PyTypeObject PyList_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LIST_SUBCLASS, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LIST_SUBCLASS | + _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE, /* tp_flags */ list___init____doc__, /* tp_doc */ (traverseproc)list_traverse, /* tp_traverse */ (inquiry)_list_clear, /* tp_clear */ diff --git a/contrib/tools/python3/src/Objects/longobject.c b/contrib/tools/python3/src/Objects/longobject.c index cf13b2c430..685bd56096 100644 --- a/contrib/tools/python3/src/Objects/longobject.c +++ b/contrib/tools/python3/src/Objects/longobject.c @@ -3,8 +3,11 @@ /* XXX The functional organization of this file is terrible */ #include "Python.h" -#include "pycore_interp.h" // _PY_NSMALLPOSINTS -#include "pycore_pystate.h" // _Py_IsMainInterpreter() +#include "pycore_bitutils.h" // _Py_popcount32() +#include "pycore_interp.h" // _PY_NSMALLPOSINTS +#include "pycore_long.h" // __PyLong_GetSmallInt_internal() +#include "pycore_object.h" // _PyObject_InitVar() +#include "pycore_pystate.h" // _Py_IsMainInterpreter() #include "longintrepr.h" #include <float.h> @@ -17,8 +20,8 @@ class int "PyObject *" "&PyLong_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/ -#define NSMALLPOSINTS _PY_NSMALLPOSINTS #define NSMALLNEGINTS _PY_NSMALLNEGINTS +#define NSMALLPOSINTS _PY_NSMALLPOSINTS _Py_IDENTIFIER(little); _Py_IDENTIFIER(big); @@ -29,10 +32,6 @@ _Py_IDENTIFIER(big); (Py_SIZE(x) == 0 ? (sdigit)0 : \ (sdigit)(x)->ob_digit[0])) -PyObject *_PyLong_Zero = NULL; -PyObject *_PyLong_One = NULL; - -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 #define IS_SMALL_INT(ival) (-NSMALLNEGINTS <= (ival) && (ival) < NSMALLPOSINTS) #define IS_SMALL_UINT(ival) ((ival) < NSMALLPOSINTS) @@ -40,8 +39,7 @@ static PyObject * get_small_int(sdigit ival) { assert(IS_SMALL_INT(ival)); - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *v = (PyObject*)tstate->interp->small_ints[ival + NSMALLNEGINTS]; + PyObject *v = __PyLong_GetSmallInt_internal(ival); Py_INCREF(v); return v; } @@ -58,12 +56,6 @@ maybe_small_long(PyLongObject *v) } return v; } -#else -#define IS_SMALL_INT(ival) 0 -#define IS_SMALL_UINT(ival) 0 -#define get_small_int(ival) (Py_UNREACHABLE(), NULL) -#define maybe_small_long(val) (val) -#endif /* If a freshly-allocated int is already shared, it must be a small integer, so negating it must go to PyLong_FromLong */ @@ -119,123 +111,6 @@ long_normalize(PyLongObject *v) return v; } -/* _PyLong_FromNbInt: Convert the given object to a PyLongObject - using the nb_int slot, if available. Raise TypeError if either the - nb_int slot is not available or the result of the call to nb_int - returns something not of type int. -*/ -PyObject * -_PyLong_FromNbInt(PyObject *integral) -{ - PyNumberMethods *nb; - PyObject *result; - - /* Fast path for the case that we already have an int. */ - if (PyLong_CheckExact(integral)) { - Py_INCREF(integral); - return integral; - } - - nb = Py_TYPE(integral)->tp_as_number; - if (nb == NULL || nb->nb_int == NULL) { - PyErr_Format(PyExc_TypeError, - "an integer is required (got type %.200s)", - Py_TYPE(integral)->tp_name); - return NULL; - } - - /* Convert using the nb_int slot, which should return something - of exact type int. */ - result = nb->nb_int(integral); - if (!result || PyLong_CheckExact(result)) - return result; - if (!PyLong_Check(result)) { - PyErr_Format(PyExc_TypeError, - "__int__ returned non-int (type %.200s)", - Py_TYPE(result)->tp_name); - Py_DECREF(result); - return NULL; - } - /* Issue #17576: warn if 'result' not of exact type int. */ - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "__int__ returned non-int (type %.200s). " - "The ability to return an instance of a strict subclass of int " - "is deprecated, and may be removed in a future version of Python.", - Py_TYPE(result)->tp_name)) { - Py_DECREF(result); - return NULL; - } - return result; -} - -/* Convert the given object to a PyLongObject using the nb_index or - nb_int slots, if available (the latter is deprecated). - Raise TypeError if either nb_index and nb_int slots are not - available or the result of the call to nb_index or nb_int - returns something not of type int. - Should be replaced with PyNumber_Index after the end of the - deprecation period. -*/ -PyObject * -_PyLong_FromNbIndexOrNbInt(PyObject *integral) -{ - PyNumberMethods *nb; - PyObject *result; - - /* Fast path for the case that we already have an int. */ - if (PyLong_CheckExact(integral)) { - Py_INCREF(integral); - return integral; - } - - nb = Py_TYPE(integral)->tp_as_number; - if (nb == NULL || (nb->nb_index == NULL && nb->nb_int == NULL)) { - PyErr_Format(PyExc_TypeError, - "an integer is required (got type %.200s)", - Py_TYPE(integral)->tp_name); - return NULL; - } - - if (nb->nb_index) { - /* Convert using the nb_index slot, which should return something - of exact type int. */ - result = nb->nb_index(integral); - if (!result || PyLong_CheckExact(result)) - return result; - if (!PyLong_Check(result)) { - PyErr_Format(PyExc_TypeError, - "__index__ returned non-int (type %.200s)", - Py_TYPE(result)->tp_name); - Py_DECREF(result); - return NULL; - } - /* Issue #17576: warn if 'result' not of exact type int. */ - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "__index__ returned non-int (type %.200s). " - "The ability to return an instance of a strict subclass of int " - "is deprecated, and may be removed in a future version of Python.", - Py_TYPE(result)->tp_name)) - { - Py_DECREF(result); - return NULL; - } - return result; - } - - result = _PyLong_FromNbInt(integral); - if (result && PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "an integer is required (got type %.200s). " - "Implicit conversion to integers using __int__ is deprecated, " - "and may be removed in a future version of Python.", - Py_TYPE(integral)->tp_name)) - { - Py_DECREF(result); - return NULL; - } - return result; -} - - /* Allocate a new int object with size digits. Return NULL and set exception if we run out of memory. */ @@ -256,13 +131,14 @@ _PyLong_New(Py_ssize_t size) "too many digits in integer"); return NULL; } - result = PyObject_MALLOC(offsetof(PyLongObject, ob_digit) + + result = PyObject_Malloc(offsetof(PyLongObject, ob_digit) + size*sizeof(digit)); if (!result) { PyErr_NoMemory(); return NULL; } - return (PyLongObject*)PyObject_INIT_VAR(result, &PyLong_Type, size); + _PyObject_InitVar((PyVarObject*)result, &PyLong_Type, size); + return result; } PyObject * @@ -480,7 +356,7 @@ PyLong_FromDouble(double dval) #define PY_ABS_LONG_MIN (0-(unsigned long)LONG_MIN) #define PY_ABS_SSIZE_T_MIN (0-(size_t)PY_SSIZE_T_MIN) -/* Get a C long int from an int object or any object that has an __int__ +/* Get a C long int from an int object or any object that has an __index__ method. On overflow, return -1 and set *overflow to 1 or -1 depending on the sign of @@ -499,7 +375,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) long res; Py_ssize_t i; int sign; - int do_decref = 0; /* if nb_int was called */ + int do_decref = 0; /* if PyNumber_Index was called */ *overflow = 0; if (vv == NULL) { @@ -511,7 +387,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) v = (PyLongObject *)vv; } else { - v = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(vv); + v = (PyLongObject *)_PyNumber_Index(vv); if (v == NULL) return -1; do_decref = 1; @@ -566,7 +442,7 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow) return res; } -/* Get a C long int from an int object or any object that has an __int__ +/* Get a C long int from an int object or any object that has an __index__ method. Return -1 and set an error if overflow occurs. */ long @@ -583,7 +459,7 @@ PyLong_AsLong(PyObject *obj) return result; } -/* Get a C int from an int object or any object that has an __int__ +/* Get a C int from an int object or any object that has an __index__ method. Return -1 and set an error if overflow occurs. */ int @@ -791,7 +667,7 @@ PyLong_AsUnsignedLongMask(PyObject *op) return _PyLong_AsUnsignedLongMask(op); } - lo = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(op); + lo = (PyLongObject *)_PyNumber_Index(op); if (lo == NULL) return (unsigned long)-1; @@ -811,6 +687,13 @@ _PyLong_Sign(PyObject *vv) return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1); } +static int +bit_length_digit(digit x) +{ + Py_BUILD_ASSERT(PyLong_SHIFT <= sizeof(unsigned long) * 8); + return _Py_bit_length((unsigned long)x); +} + size_t _PyLong_NumBits(PyObject *vv) { @@ -828,7 +711,7 @@ _PyLong_NumBits(PyObject *vv) if ((size_t)(ndigits - 1) > SIZE_MAX / (size_t)PyLong_SHIFT) goto Overflow; result = (size_t)(ndigits - 1) * (size_t)PyLong_SHIFT; - msd_bits = _Py_bit_length(msd); + msd_bits = bit_length_digit(msd); if (SIZE_MAX - msd_bits < result) goto Overflow; result += msd_bits; @@ -1230,7 +1113,7 @@ PyLong_FromSsize_t(Py_ssize_t ival) } /* Get a C long long int from an int object or any object that has an - __int__ method. Return -1 and set an error if overflow occurs. */ + __index__ method. Return -1 and set an error if overflow occurs. */ long long PyLong_AsLongLong(PyObject *vv) @@ -1238,7 +1121,7 @@ PyLong_AsLongLong(PyObject *vv) PyLongObject *v; long long bytes; int res; - int do_decref = 0; /* if nb_int was called */ + int do_decref = 0; /* if PyNumber_Index was called */ if (vv == NULL) { PyErr_BadInternalCall(); @@ -1249,7 +1132,7 @@ PyLong_AsLongLong(PyObject *vv) v = (PyLongObject *)vv; } else { - v = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(vv); + v = (PyLongObject *)_PyNumber_Index(vv); if (v == NULL) return -1; do_decref = 1; @@ -1364,7 +1247,7 @@ PyLong_AsUnsignedLongLongMask(PyObject *op) return _PyLong_AsUnsignedLongLongMask(op); } - lo = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(op); + lo = (PyLongObject *)_PyNumber_Index(op); if (lo == NULL) return (unsigned long long)-1; @@ -1374,7 +1257,7 @@ PyLong_AsUnsignedLongLongMask(PyObject *op) } /* Get a C long long int from an int object or any object that has an - __int__ method. + __index__ method. On overflow, return -1 and set *overflow to 1 or -1 depending on the sign of the result. Otherwise *overflow is 0. @@ -1392,7 +1275,7 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) long long res; Py_ssize_t i; int sign; - int do_decref = 0; /* if nb_int was called */ + int do_decref = 0; /* if PyNumber_Index was called */ *overflow = 0; if (vv == NULL) { @@ -1404,7 +1287,7 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) v = (PyLongObject *)vv; } else { - v = (PyLongObject *)_PyLong_FromNbIndexOrNbInt(vv); + v = (PyLongObject *)_PyNumber_Index(vv); if (v == NULL) return -1; do_decref = 1; @@ -1938,7 +1821,7 @@ long_format_binary(PyObject *aa, int base, int alternate, return -1; } size_a_in_bits = (size_a - 1) * PyLong_SHIFT + - _Py_bit_length(a->ob_digit[size_a - 1]); + bit_length_digit(a->ob_digit[size_a - 1]); /* Allow 1 character for a '-' sign. */ sz = negative + (size_a_in_bits + (bits - 1)) / bits; } @@ -2611,17 +2494,6 @@ _PyLong_FromBytes(const char *s, Py_ssize_t len, int base) } PyObject * -PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base) -{ - PyObject *v, *unicode = PyUnicode_FromWideChar(u, length); - if (unicode == NULL) - return NULL; - v = PyLong_FromUnicodeObject(unicode, base); - Py_DECREF(unicode); - return v; -} - -PyObject * PyLong_FromUnicodeObject(PyObject *u, int base) { PyObject *result, *asciidig; @@ -2677,8 +2549,9 @@ long_divrem(PyLongObject *a, PyLongObject *b, if (*prem == NULL) { return -1; } - Py_INCREF(_PyLong_Zero); - *pdiv = (PyLongObject*)_PyLong_Zero; + PyObject *zero = _PyLong_GetZero(); + Py_INCREF(zero); + *pdiv = (PyLongObject*)zero; return 0; } if (size_b == 1) { @@ -2758,7 +2631,7 @@ x_divrem(PyLongObject *v1, PyLongObject *w1, PyLongObject **prem) /* normalize: shift w1 left so that its top digit is >= PyLong_BASE/2. shift v1 left by the same amount. Results go into w and v. */ - d = PyLong_SHIFT - _Py_bit_length(w1->ob_digit[size_w-1]); + d = PyLong_SHIFT - bit_length_digit(w1->ob_digit[size_w-1]); carry = v_lshift(w->ob_digit, w1->ob_digit, size_w, d); assert(carry == 0); carry = v_lshift(v->ob_digit, v1->ob_digit, size_v, d); @@ -2880,7 +2753,7 @@ _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e) *e = 0; return 0.0; } - a_bits = _Py_bit_length(a->ob_digit[a_size-1]); + a_bits = bit_length_digit(a->ob_digit[a_size-1]); /* The following is an overflow-free version of the check "if ((a_size - 1) * PyLong_SHIFT + a_bits > PY_SSIZE_T_MAX) ..." */ if (a_size >= (PY_SSIZE_T_MAX - 1) / PyLong_SHIFT + 1 && @@ -3787,7 +3660,7 @@ l_divmod(PyLongObject *v, PyLongObject *w, Py_DECREF(div); return -1; } - temp = (PyLongObject *) long_sub(div, (PyLongObject *)_PyLong_One); + temp = (PyLongObject *) long_sub(div, (PyLongObject *)_PyLong_GetOne()); if (temp == NULL) { Py_DECREF(mod); Py_DECREF(div); @@ -3973,8 +3846,8 @@ long_true_divide(PyObject *v, PyObject *w) /* Extreme underflow */ goto underflow_or_zero; /* Next line is now safe from overflowing a Py_ssize_t */ - diff = diff * PyLong_SHIFT + _Py_bit_length(a->ob_digit[a_size - 1]) - - _Py_bit_length(b->ob_digit[b_size - 1]); + diff = diff * PyLong_SHIFT + bit_length_digit(a->ob_digit[a_size - 1]) - + bit_length_digit(b->ob_digit[b_size - 1]); /* Now diff = a_bits - b_bits. */ if (diff > DBL_MAX_EXP) goto overflow; @@ -4050,7 +3923,7 @@ long_true_divide(PyObject *v, PyObject *w) } x_size = Py_ABS(Py_SIZE(x)); assert(x_size > 0); /* result of division is never zero */ - x_bits = (x_size-1)*PyLong_SHIFT+_Py_bit_length(x->ob_digit[x_size-1]); + x_bits = (x_size-1)*PyLong_SHIFT+bit_length_digit(x->ob_digit[x_size-1]); /* The number of extra bits that have to be rounded away. */ extra_bits = Py_MAX(x_bits, DBL_MIN_EXP - shift) - DBL_MANT_DIG; @@ -4196,7 +4069,7 @@ long_invmod(PyLongObject *a, PyLongObject *n) Py_DECREF(c); Py_DECREF(n); - if (long_compare(a, (PyLongObject *)_PyLong_One)) { + if (long_compare(a, (PyLongObject *)_PyLong_GetOne())) { /* a != 1; we don't have an inverse. */ Py_DECREF(a); Py_DECREF(b); @@ -4432,7 +4305,7 @@ long_invert(PyLongObject *v) PyLongObject *x; if (Py_ABS(Py_SIZE(v)) <=1) return PyLong_FromLong(-(MEDIUM_VALUE(v)+1)); - x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_One); + x = (PyLongObject *) long_add(v, (PyLongObject *)_PyLong_GetOne()); if (x == NULL) return NULL; _PyLong_Negate(&x); @@ -4865,7 +4738,7 @@ _PyLong_GCD(PyObject *aarg, PyObject *barg) alloc_b = Py_SIZE(b); /* reduce until a fits into 2 digits */ while ((size_a = Py_SIZE(a)) > 2) { - nbits = _Py_bit_length(a->ob_digit[size_a-1]); + nbits = bit_length_digit(a->ob_digit[size_a-1]); /* extract top 2*PyLong_SHIFT bits of a into x, along with corresponding bits of b into y */ size_b = Py_SIZE(b); @@ -5224,7 +5097,8 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) /* compare twice the remainder with the divisor, to see if we need to adjust the quotient and remainder */ - twice_rem = long_lshift((PyObject *)rem, _PyLong_One); + PyObject *one = _PyLong_GetOne(); // borrowed reference + twice_rem = long_lshift((PyObject *)rem, one); if (twice_rem == NULL) goto error; if (quo_is_neg) { @@ -5241,9 +5115,9 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) if ((Py_SIZE(b) < 0 ? cmp < 0 : cmp > 0) || (cmp == 0 && quo_is_odd)) { /* fix up quotient */ if (quo_is_neg) - temp = long_sub(quo, (PyLongObject *)_PyLong_One); + temp = long_sub(quo, (PyLongObject *)one); else - temp = long_add(quo, (PyLongObject *)_PyLong_One); + temp = long_add(quo, (PyLongObject *)one); Py_DECREF(quo); quo = (PyLongObject *)temp; if (quo == NULL) @@ -5274,10 +5148,22 @@ _PyLong_DivmodNear(PyObject *a, PyObject *b) return NULL; } +/*[clinic input] +int.__round__ + + ndigits as o_ndigits: object = NULL + / + +Rounding an Integral returns itself. + +Rounding with an ndigits argument also returns an integer. +[clinic start generated code]*/ + static PyObject * -long_round(PyObject *self, PyObject *args) +int___round___impl(PyObject *self, PyObject *o_ndigits) +/*[clinic end generated code: output=954fda6b18875998 input=1614cf23ec9e18c3]*/ { - PyObject *o_ndigits=NULL, *temp, *result, *ndigits; + PyObject *temp, *result, *ndigits; /* To round an integer m to the nearest 10**n (n positive), we make use of * the divmod_near operation, defined by: @@ -5293,12 +5179,10 @@ long_round(PyObject *self, PyObject *args) * * m - divmod_near(m, 10**n)[1]. */ - if (!PyArg_ParseTuple(args, "|O", &o_ndigits)) - return NULL; if (o_ndigits == NULL) return long_long(self); - ndigits = PyNumber_Index(o_ndigits); + ndigits = _PyNumber_Index(o_ndigits); if (ndigits == NULL) return NULL; @@ -5386,7 +5270,7 @@ int_bit_length_impl(PyObject *self) return PyLong_FromLong(0); msd = ((PyLongObject *)self)->ob_digit[ndigits-1]; - msd_bits = _Py_bit_length(msd); + msd_bits = bit_length_digit(msd); if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT) return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits); @@ -5422,6 +5306,73 @@ int_bit_length_impl(PyObject *self) return NULL; } +static int +popcount_digit(digit d) +{ + // digit can be larger than uint32_t, but only PyLong_SHIFT bits + // of it will be ever used. + Py_BUILD_ASSERT(PyLong_SHIFT <= 32); + return _Py_popcount32((uint32_t)d); +} + +/*[clinic input] +int.bit_count + +Number of ones in the binary representation of the absolute value of self. + +Also known as the population count. + +>>> bin(13) +'0b1101' +>>> (13).bit_count() +3 +[clinic start generated code]*/ + +static PyObject * +int_bit_count_impl(PyObject *self) +/*[clinic end generated code: output=2e571970daf1e5c3 input=7e0adef8e8ccdf2e]*/ +{ + assert(self != NULL); + assert(PyLong_Check(self)); + + PyLongObject *z = (PyLongObject *)self; + Py_ssize_t ndigits = Py_ABS(Py_SIZE(z)); + Py_ssize_t bit_count = 0; + + /* Each digit has up to PyLong_SHIFT ones, so the accumulated bit count + from the first PY_SSIZE_T_MAX/PyLong_SHIFT digits can't overflow a + Py_ssize_t. */ + Py_ssize_t ndigits_fast = Py_MIN(ndigits, PY_SSIZE_T_MAX/PyLong_SHIFT); + for (Py_ssize_t i = 0; i < ndigits_fast; i++) { + bit_count += popcount_digit(z->ob_digit[i]); + } + + PyObject *result = PyLong_FromSsize_t(bit_count); + if (result == NULL) { + return NULL; + } + + /* Use Python integers if bit_count would overflow. */ + for (Py_ssize_t i = ndigits_fast; i < ndigits; i++) { + PyObject *x = PyLong_FromLong(popcount_digit(z->ob_digit[i])); + if (x == NULL) { + goto error; + } + PyObject *y = long_add((PyLongObject *)result, (PyLongObject *)x); + Py_DECREF(x); + if (y == NULL) { + goto error; + } + Py_DECREF(result); + result = y; + } + + return result; + + error: + Py_DECREF(result); + return NULL; +} /*[clinic input] int.as_integer_ratio @@ -5448,7 +5399,7 @@ int_as_integer_ratio_impl(PyObject *self) if (numerator == NULL) { return NULL; } - ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_One); + ratio_tuple = PyTuple_Pack(2, numerator, _PyLong_GetOne()); Py_DECREF(numerator); return ratio_tuple; } @@ -5578,6 +5529,7 @@ static PyMethodDef long_methods[] = { {"conjugate", long_long_meth, METH_NOARGS, "Returns self, the complex conjugate of any int."}, INT_BIT_LENGTH_METHODDEF + INT_BIT_COUNT_METHODDEF INT_TO_BYTES_METHODDEF INT_FROM_BYTES_METHODDEF INT_AS_INTEGER_RATIO_METHODDEF @@ -5587,9 +5539,7 @@ static PyMethodDef long_methods[] = { "Flooring an Integral returns itself."}, {"__ceil__", long_long_meth, METH_NOARGS, "Ceiling of an Integral returns itself."}, - {"__round__", (PyCFunction)long_round, METH_VARARGS, - "Rounding an Integral returns itself.\n" - "Rounding with an ndigits argument also returns an integer."}, + INT___ROUND___METHODDEF INT___GETNEWARGS___METHODDEF INT___FORMAT___METHODDEF INT___SIZEOF___METHODDEF @@ -5690,7 +5640,8 @@ PyTypeObject PyLong_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_LONG_SUBCLASS, /* tp_flags */ + Py_TPFLAGS_LONG_SUBCLASS | + _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ long_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -5753,9 +5704,8 @@ PyLong_GetInfo(void) } int -_PyLong_Init(PyThreadState *tstate) +_PyLong_Init(PyInterpreterState *interp) { -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 for (Py_ssize_t i=0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) { sdigit ival = (sdigit)i - NSMALLNEGINTS; int size = (ival < 0) ? -1 : ((ival == 0) ? 0 : 1); @@ -5768,43 +5718,28 @@ _PyLong_Init(PyThreadState *tstate) Py_SET_SIZE(v, size); v->ob_digit[0] = (digit)abs(ival); - tstate->interp->small_ints[i] = v; + interp->small_ints[i] = v; } -#endif - - if (_Py_IsMainInterpreter(tstate)) { - _PyLong_Zero = PyLong_FromLong(0); - if (_PyLong_Zero == NULL) { - return 0; - } + return 0; +} - _PyLong_One = PyLong_FromLong(1); - if (_PyLong_One == NULL) { - return 0; - } - /* initialize int_info */ - if (Int_InfoType.tp_name == NULL) { - if (PyStructSequence_InitType2(&Int_InfoType, &int_info_desc) < 0) { - return 0; - } +int +_PyLong_InitTypes(void) +{ + /* initialize int_info */ + if (Int_InfoType.tp_name == NULL) { + if (PyStructSequence_InitType2(&Int_InfoType, &int_info_desc) < 0) { + return -1; } } - - return 1; + return 0; } void -_PyLong_Fini(PyThreadState *tstate) +_PyLong_Fini(PyInterpreterState *interp) { - if (_Py_IsMainInterpreter(tstate)) { - Py_CLEAR(_PyLong_One); - Py_CLEAR(_PyLong_Zero); - } - -#if NSMALLNEGINTS + NSMALLPOSINTS > 0 for (Py_ssize_t i = 0; i < NSMALLNEGINTS + NSMALLPOSINTS; i++) { - Py_CLEAR(tstate->interp->small_ints[i]); + Py_CLEAR(interp->small_ints[i]); } -#endif } diff --git a/contrib/tools/python3/src/Objects/memoryobject.c b/contrib/tools/python3/src/Objects/memoryobject.c index 682bbe8a61..913d358062 100644 --- a/contrib/tools/python3/src/Objects/memoryobject.c +++ b/contrib/tools/python3/src/Objects/memoryobject.c @@ -238,12 +238,6 @@ PyTypeObject _PyManagedBuffer_Type = { #define REQ_FORMAT(flags) (flags&PyBUF_FORMAT) -PyDoc_STRVAR(memory_doc, -"memoryview(object)\n--\n\ -\n\ -Create a new memoryview object which references the given object."); - - /**************************************************************************/ /* Copy memoryview buffers */ /**************************************************************************/ @@ -961,18 +955,20 @@ PyMemoryView_GetContiguous(PyObject *obj, int buffertype, char order) } -static PyObject * -memory_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) -{ - PyObject *obj; - static char *kwlist[] = {"object", NULL}; +/*[clinic input] +@classmethod +memoryview.__new__ - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:memoryview", kwlist, - &obj)) { - return NULL; - } + object: object + +Create a new memoryview object which references the given object. +[clinic start generated code]*/ - return PyMemoryView_FromObject(obj); +static PyObject * +memoryview_impl(PyTypeObject *type, PyObject *object) +/*[clinic end generated code: output=7de78e184ed66db8 input=f04429eb0bdf8c6e]*/ +{ + return PyMemoryView_FromObject(object); } @@ -1062,8 +1058,15 @@ _memory_release(PyMemoryViewObject *self) return -1; } +/*[clinic input] +memoryview.release + +Release the underlying buffer exposed by the memoryview object. +[clinic start generated code]*/ + static PyObject * -memory_release(PyMemoryViewObject *self, PyObject *noargs) +memoryview_release_impl(PyMemoryViewObject *self) +/*[clinic end generated code: output=d0b7e3ba95b7fcb9 input=bc71d1d51f4a52f0]*/ { if (_memory_release(self) < 0) return NULL; @@ -1108,7 +1111,7 @@ memory_enter(PyObject *self, PyObject *args) static PyObject * memory_exit(PyObject *self, PyObject *args) { - return memory_release((PyMemoryViewObject *)self, NULL); + return memoryview_release_impl((PyMemoryViewObject *)self); } @@ -1352,26 +1355,25 @@ zero_in_shape(PyMemoryViewObject *mv) All casts must result in views that will have the exact byte size of the original input. Otherwise, an error is raised. */ +/*[clinic input] +memoryview.cast + + format: unicode + shape: object = NULL + +Cast a memoryview to a new format or shape. +[clinic start generated code]*/ + static PyObject * -memory_cast(PyMemoryViewObject *self, PyObject *args, PyObject *kwds) +memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format, + PyObject *shape) +/*[clinic end generated code: output=bae520b3a389cbab input=138936cc9041b1a3]*/ { - static char *kwlist[] = {"format", "shape", NULL}; PyMemoryViewObject *mv = NULL; - PyObject *shape = NULL; - PyObject *format; Py_ssize_t ndim = 1; CHECK_RELEASED(self); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist, - &format, &shape)) { - return NULL; - } - if (!PyUnicode_Check(format)) { - PyErr_SetString(PyExc_TypeError, - "memoryview: format argument must be a string"); - return NULL; - } if (!MV_C_CONTIGUOUS(self->flags)) { PyErr_SetString(PyExc_TypeError, "memoryview: casts are restricted to C-contiguous views"); @@ -1415,8 +1417,15 @@ error: return NULL; } +/*[clinic input] +memoryview.toreadonly + +Return a readonly version of the memoryview. +[clinic start generated code]*/ + static PyObject * -memory_toreadonly(PyMemoryViewObject *self, PyObject *noargs) +memoryview_toreadonly_impl(PyMemoryViewObject *self) +/*[clinic end generated code: output=2c7e056f04c99e62 input=dc06d20f19ba236f]*/ { CHECK_RELEASED(self); /* Even if self is already readonly, we still need to create a new @@ -1578,7 +1587,7 @@ pylong_as_ld(PyObject *item) PyObject *tmp; long ld; - tmp = PyNumber_Index(item); + tmp = _PyNumber_Index(item); if (tmp == NULL) return -1; @@ -1593,7 +1602,7 @@ pylong_as_lu(PyObject *item) PyObject *tmp; unsigned long lu; - tmp = PyNumber_Index(item); + tmp = _PyNumber_Index(item); if (tmp == NULL) return (unsigned long)-1; @@ -1608,7 +1617,7 @@ pylong_as_lld(PyObject *item) PyObject *tmp; long long lld; - tmp = PyNumber_Index(item); + tmp = _PyNumber_Index(item); if (tmp == NULL) return -1; @@ -1623,7 +1632,7 @@ pylong_as_llu(PyObject *item) PyObject *tmp; unsigned long long llu; - tmp = PyNumber_Index(item); + tmp = _PyNumber_Index(item); if (tmp == NULL) return (unsigned long long)-1; @@ -1638,7 +1647,7 @@ pylong_as_zd(PyObject *item) PyObject *tmp; Py_ssize_t zd; - tmp = PyNumber_Index(item); + tmp = _PyNumber_Index(item); if (tmp == NULL) return -1; @@ -1653,7 +1662,7 @@ pylong_as_zu(PyObject *item) PyObject *tmp; size_t zu; - tmp = PyNumber_Index(item); + tmp = _PyNumber_Index(item); if (tmp == NULL) return (size_t)-1; @@ -2109,13 +2118,20 @@ tolist_rec(const char *ptr, Py_ssize_t ndim, const Py_ssize_t *shape, /* Return a list representation of the memoryview. Currently only buffers with native format strings are supported. */ +/*[clinic input] +memoryview.tolist + +Return the data in the buffer as a list of elements. +[clinic start generated code]*/ + static PyObject * -memory_tolist(PyMemoryViewObject *mv, PyObject *noargs) +memoryview_tolist_impl(PyMemoryViewObject *self) +/*[clinic end generated code: output=a6cda89214fd5a1b input=21e7d0c1860b211a]*/ { - const Py_buffer *view = &(mv->view); + const Py_buffer *view = &self->view; const char *fmt; - CHECK_RELEASED(mv); + CHECK_RELEASED(self); fmt = adjust_fmt(view); if (fmt == NULL) @@ -2135,21 +2151,30 @@ memory_tolist(PyMemoryViewObject *mv, PyObject *noargs) } } +/*[clinic input] +memoryview.tobytes + + order: str(accept={str, NoneType}, c_default="NULL") = 'C' + +Return the data in the buffer as a byte string. + +Order can be {'C', 'F', 'A'}. When order is 'C' or 'F', the data of the +original array is converted to C or Fortran order. For contiguous views, +'A' returns an exact copy of the physical memory. In particular, in-memory +Fortran order is preserved. For non-contiguous views, the data is converted +to C first. order=None is the same as order='C'. +[clinic start generated code]*/ + static PyObject * -memory_tobytes(PyMemoryViewObject *self, PyObject *args, PyObject *kwds) +memoryview_tobytes_impl(PyMemoryViewObject *self, const char *order) +/*[clinic end generated code: output=1288b62560a32a23 input=0efa3ddaeda573a8]*/ { - static char *kwlist[] = {"order", NULL}; Py_buffer *src = VIEW_ADDR(self); - char *order = NULL; char ord = 'C'; PyObject *bytes; CHECK_RELEASED(self); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|z", kwlist, &order)) { - return NULL; - } - if (order) { if (strcmp(order, "F") == 0) { ord = 'F'; @@ -3122,43 +3147,125 @@ static PyGetSetDef memory_getsetlist[] = { {NULL, NULL, NULL, NULL}, }; -PyDoc_STRVAR(memory_release_doc, -"release($self, /)\n--\n\ -\n\ -Release the underlying buffer exposed by the memoryview object."); -PyDoc_STRVAR(memory_tobytes_doc, -"tobytes($self, /, order=None)\n--\n\ -\n\ -Return the data in the buffer as a byte string. Order can be {'C', 'F', 'A'}.\n\ -When order is 'C' or 'F', the data of the original array is converted to C or\n\ -Fortran order. For contiguous views, 'A' returns an exact copy of the physical\n\ -memory. In particular, in-memory Fortran order is preserved. For non-contiguous\n\ -views, the data is converted to C first. order=None is the same as order='C'."); -PyDoc_STRVAR(memory_tolist_doc, -"tolist($self, /)\n--\n\ -\n\ -Return the data in the buffer as a list of elements."); -PyDoc_STRVAR(memory_cast_doc, -"cast($self, /, format, *, shape)\n--\n\ -\n\ -Cast a memoryview to a new format or shape."); -PyDoc_STRVAR(memory_toreadonly_doc, -"toreadonly($self, /)\n--\n\ -\n\ -Return a readonly version of the memoryview."); static PyMethodDef memory_methods[] = { - {"release", (PyCFunction)memory_release, METH_NOARGS, memory_release_doc}, - {"tobytes", (PyCFunction)(void(*)(void))memory_tobytes, METH_VARARGS|METH_KEYWORDS, memory_tobytes_doc}, + MEMORYVIEW_RELEASE_METHODDEF + MEMORYVIEW_TOBYTES_METHODDEF MEMORYVIEW_HEX_METHODDEF - {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, memory_tolist_doc}, - {"cast", (PyCFunction)(void(*)(void))memory_cast, METH_VARARGS|METH_KEYWORDS, memory_cast_doc}, - {"toreadonly", (PyCFunction)memory_toreadonly, METH_NOARGS, memory_toreadonly_doc}, + MEMORYVIEW_TOLIST_METHODDEF + MEMORYVIEW_CAST_METHODDEF + MEMORYVIEW_TOREADONLY_METHODDEF {"__enter__", memory_enter, METH_NOARGS, NULL}, {"__exit__", memory_exit, METH_VARARGS, NULL}, {NULL, NULL} }; +/**************************************************************************/ +/* Memoryview Iterator */ +/**************************************************************************/ + +static PyTypeObject PyMemoryIter_Type; + +typedef struct { + PyObject_HEAD + Py_ssize_t it_index; + PyMemoryViewObject *it_seq; // Set to NULL when iterator is exhausted + Py_ssize_t it_length; + const char *it_fmt; +} memoryiterobject; + +static void +memoryiter_dealloc(memoryiterobject *it) +{ + _PyObject_GC_UNTRACK(it); + Py_XDECREF(it->it_seq); + PyObject_GC_Del(it); +} + +static int +memoryiter_traverse(memoryiterobject *it, visitproc visit, void *arg) +{ + Py_VISIT(it->it_seq); + return 0; +} + +static PyObject * +memoryiter_next(memoryiterobject *it) +{ + PyMemoryViewObject *seq; + seq = it->it_seq; + if (seq == NULL) { + return NULL; + } + + if (it->it_index < it->it_length) { + CHECK_RELEASED(seq); + Py_buffer *view = &(seq->view); + char *ptr = (char *)seq->view.buf; + + ptr += view->strides[0] * it->it_index++; + ptr = ADJUST_PTR(ptr, view->suboffsets, 0); + if (ptr == NULL) { + return NULL; + } + return unpack_single(ptr, it->it_fmt); + } + + it->it_seq = NULL; + Py_DECREF(seq); + return NULL; +} + +static PyObject * +memory_iter(PyObject *seq) +{ + if (!PyMemoryView_Check(seq)) { + PyErr_BadInternalCall(); + return NULL; + } + PyMemoryViewObject *obj = (PyMemoryViewObject *)seq; + int ndims = obj->view.ndim; + if (ndims == 0) { + PyErr_SetString(PyExc_TypeError, "invalid indexing of 0-dim memory"); + return NULL; + } + if (ndims != 1) { + PyErr_SetString(PyExc_NotImplementedError, + "multi-dimensional sub-views are not implemented"); + return NULL; + } + + const char *fmt = adjust_fmt(&obj->view); + if (fmt == NULL) { + return NULL; + } + + memoryiterobject *it; + it = PyObject_GC_New(memoryiterobject, &PyMemoryIter_Type); + if (it == NULL) { + return NULL; + } + it->it_fmt = fmt; + it->it_length = memory_length(obj); + it->it_index = 0; + Py_INCREF(seq); + it->it_seq = obj; + _PyObject_GC_TRACK(it); + return (PyObject *)it; +} + +static PyTypeObject PyMemoryIter_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "memory_iterator", + .tp_basicsize = sizeof(memoryiterobject), + // methods + .tp_dealloc = (destructor)memoryiter_dealloc, + .tp_getattro = PyObject_GenericGetAttr, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = (traverseproc)memoryiter_traverse, + .tp_iter = PyObject_SelfIter, + .tp_iternext = (iternextfunc)memoryiter_next, +}; PyTypeObject PyMemoryView_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) @@ -3180,13 +3287,14 @@ PyTypeObject PyMemoryView_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ &memory_as_buffer, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ - memory_doc, /* tp_doc */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_SEQUENCE, /* tp_flags */ + memoryview__doc__, /* tp_doc */ (traverseproc)memory_traverse, /* tp_traverse */ (inquiry)memory_clear, /* tp_clear */ memory_richcompare, /* tp_richcompare */ offsetof(PyMemoryViewObject, weakreflist),/* tp_weaklistoffset */ - 0, /* tp_iter */ + memory_iter, /* tp_iter */ 0, /* tp_iternext */ memory_methods, /* tp_methods */ 0, /* tp_members */ @@ -3198,5 +3306,5 @@ PyTypeObject PyMemoryView_Type = { 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ - memory_new, /* tp_new */ + memoryview, /* tp_new */ }; diff --git a/contrib/tools/python3/src/Objects/moduleobject.c b/contrib/tools/python3/src/Objects/moduleobject.c index ee4ed97588..b69e5cedbb 100644 --- a/contrib/tools/python3/src/Objects/moduleobject.c +++ b/contrib/tools/python3/src/Objects/moduleobject.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_interp.h" // PyInterpreterState.importlib #include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_moduleobject.h" // _PyModule_GetDef() #include "structmember.h" // PyMemberDef static Py_ssize_t max_module_number; @@ -11,15 +12,9 @@ static Py_ssize_t max_module_number; _Py_IDENTIFIER(__doc__); _Py_IDENTIFIER(__name__); _Py_IDENTIFIER(__spec__); - -typedef struct { - PyObject_HEAD - PyObject *md_dict; - struct PyModuleDef *md_def; - void *md_state; - PyObject *md_weaklist; - PyObject *md_name; /* for logging purposes after md_dict is cleared */ -} PyModuleObject; +_Py_IDENTIFIER(__dict__); +_Py_IDENTIFIER(__dir__); +_Py_IDENTIFIER(__annotations__); static PyMemberDef module_members[] = { {"__dict__", T_OBJECT, offsetof(PyModuleObject, md_dict), READONLY}, @@ -35,6 +30,19 @@ PyTypeObject PyModuleDef_Type = { }; +int +_PyModule_IsExtension(PyObject *obj) +{ + if (!PyModule_Check(obj)) { + return 0; + } + PyModuleObject *module = (PyModuleObject*)obj; + + struct PyModuleDef *def = module->md_def; + return (def != NULL && def->m_methods != NULL); +} + + PyObject* PyModuleDef_Init(struct PyModuleDef* def) { @@ -211,7 +219,7 @@ _PyModule_CreateInitialized(struct PyModuleDef* module, int module_api_version) return NULL; if (module->m_size > 0) { - m->md_state = PyMem_MALLOC(module->m_size); + m->md_state = PyMem_Malloc(module->m_size); if (!m->md_state) { PyErr_NoMemory(); Py_DECREF(m); @@ -377,7 +385,7 @@ PyModule_ExecDef(PyObject *module, PyModuleDef *def) if (md->md_state == NULL) { /* Always set a state pointer; this serves as a marker to skip * multiple initialization (importlib.reload() is no-op) */ - md->md_state = PyMem_MALLOC(def->m_size); + md->md_state = PyMem_Malloc(def->m_size); if (!md->md_state) { PyErr_NoMemory(); return -1; @@ -456,14 +464,11 @@ PyModule_SetDocString(PyObject *m, const char *doc) PyObject * PyModule_GetDict(PyObject *m) { - PyObject *d; if (!PyModule_Check(m)) { PyErr_BadInternalCall(); return NULL; } - d = ((PyModuleObject *)m) -> md_dict; - assert(d != NULL); - return d; + return _PyModule_GetDict(m); } PyObject* @@ -476,11 +481,13 @@ PyModule_GetNameObject(PyObject *m) return NULL; } d = ((PyModuleObject *)m)->md_dict; - if (d == NULL || - (name = _PyDict_GetItemId(d, &PyId___name__)) == NULL || + if (d == NULL || !PyDict_Check(d) || + (name = _PyDict_GetItemIdWithError(d, &PyId___name__)) == NULL || !PyUnicode_Check(name)) { - PyErr_SetString(PyExc_SystemError, "nameless module"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_SystemError, "nameless module"); + } return NULL; } Py_INCREF(name); @@ -509,10 +516,12 @@ PyModule_GetFilenameObject(PyObject *m) } d = ((PyModuleObject *)m)->md_dict; if (d == NULL || - (fileobj = _PyDict_GetItemId(d, &PyId___file__)) == NULL || + (fileobj = _PyDict_GetItemIdWithError(d, &PyId___file__)) == NULL || !PyUnicode_Check(fileobj)) { - PyErr_SetString(PyExc_SystemError, "module filename missing"); + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_SystemError, "module filename missing"); + } return NULL; } Py_INCREF(fileobj); @@ -539,7 +548,7 @@ PyModule_GetDef(PyObject* m) PyErr_BadArgument(); return NULL; } - return ((PyModuleObject *)m)->md_def; + return _PyModule_GetDef(m); } void* @@ -549,7 +558,7 @@ PyModule_GetState(PyObject* m) PyErr_BadArgument(); return NULL; } - return ((PyModuleObject *)m)->md_state; + return _PyModule_GetState(m); } void @@ -677,7 +686,7 @@ module_dealloc(PyModuleObject *m) Py_XDECREF(m->md_dict); Py_XDECREF(m->md_name); if (m->md_state != NULL) - PyMem_FREE(m->md_state); + PyMem_Free(m->md_state); Py_TYPE(m)->tp_free((PyObject *)m); } @@ -721,14 +730,21 @@ module_getattro(PyModuleObject *m, PyObject *name) PyErr_Clear(); if (m->md_dict) { _Py_IDENTIFIER(__getattr__); - getattr = _PyDict_GetItemId(m->md_dict, &PyId___getattr__); + getattr = _PyDict_GetItemIdWithError(m->md_dict, &PyId___getattr__); if (getattr) { return PyObject_CallOneArg(getattr, name); } - mod_name = _PyDict_GetItemId(m->md_dict, &PyId___name__); + if (PyErr_Occurred()) { + return NULL; + } + mod_name = _PyDict_GetItemIdWithError(m->md_dict, &PyId___name__); if (mod_name && PyUnicode_Check(mod_name)) { Py_INCREF(mod_name); - PyObject *spec = _PyDict_GetItemId(m->md_dict, &PyId___spec__); + PyObject *spec = _PyDict_GetItemIdWithError(m->md_dict, &PyId___spec__); + if (spec == NULL && PyErr_Occurred()) { + Py_DECREF(mod_name); + return NULL; + } Py_XINCREF(spec); if (_PyModuleSpec_IsInitializing(spec)) { PyErr_Format(PyExc_AttributeError, @@ -746,6 +762,9 @@ module_getattro(PyModuleObject *m, PyObject *name) Py_DECREF(mod_name); return NULL; } + else if (PyErr_Occurred()) { + return NULL; + } } PyErr_Format(PyExc_AttributeError, "module has no attribute '%U'", name); @@ -791,8 +810,6 @@ module_clear(PyModuleObject *m) static PyObject * module_dir(PyObject *self, PyObject *args) { - _Py_IDENTIFIER(__dict__); - _Py_IDENTIFIER(__dir__); PyObject *result = NULL; PyObject *dict = _PyObject_GetAttrId(self, &PyId___dict__); @@ -807,11 +824,7 @@ module_dir(PyObject *self, PyObject *args) } } else { - const char *name = PyModule_GetName(self); - if (name) - PyErr_Format(PyExc_TypeError, - "%.200s.__dict__ is not a dictionary", - name); + PyErr_Format(PyExc_TypeError, "<module>.__dict__ is not a dictionary"); } } @@ -825,6 +838,78 @@ static PyMethodDef module_methods[] = { {0} }; +static PyObject * +module_get_annotations(PyModuleObject *m, void *Py_UNUSED(ignored)) +{ + PyObject *dict = _PyObject_GetAttrId((PyObject *)m, &PyId___dict__); + + if ((dict == NULL) || !PyDict_Check(dict)) { + PyErr_Format(PyExc_TypeError, "<module>.__dict__ is not a dictionary"); + Py_XDECREF(dict); + return NULL; + } + + PyObject *annotations; + /* there's no _PyDict_GetItemId without WithError, so let's LBYL. */ + if (_PyDict_ContainsId(dict, &PyId___annotations__)) { + annotations = _PyDict_GetItemIdWithError(dict, &PyId___annotations__); + /* + ** _PyDict_GetItemIdWithError could still fail, + ** for instance with a well-timed Ctrl-C or a MemoryError. + ** so let's be totally safe. + */ + if (annotations) { + Py_INCREF(annotations); + } + } else { + annotations = PyDict_New(); + if (annotations) { + int result = _PyDict_SetItemId(dict, &PyId___annotations__, annotations); + if (result) { + Py_CLEAR(annotations); + } + } + } + Py_DECREF(dict); + return annotations; +} + +static int +module_set_annotations(PyModuleObject *m, PyObject *value, void *Py_UNUSED(ignored)) +{ + int ret = -1; + PyObject *dict = _PyObject_GetAttrId((PyObject *)m, &PyId___dict__); + + if ((dict == NULL) || !PyDict_Check(dict)) { + PyErr_Format(PyExc_TypeError, "<module>.__dict__ is not a dictionary"); + goto exit; + } + + if (value != NULL) { + /* set */ + ret = _PyDict_SetItemId(dict, &PyId___annotations__, value); + goto exit; + } + + /* delete */ + if (!_PyDict_ContainsId(dict, &PyId___annotations__)) { + PyErr_Format(PyExc_AttributeError, "__annotations__"); + goto exit; + } + + ret = _PyDict_DelItemId(dict, &PyId___annotations__); + +exit: + Py_XDECREF(dict); + return ret; +} + + +static PyGetSetDef module_getsets[] = { + {"__annotations__", (getter)module_get_annotations, (setter)module_set_annotations}, + {NULL} +}; + PyTypeObject PyModule_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "module", /* tp_name */ @@ -856,7 +941,7 @@ PyTypeObject PyModule_Type = { 0, /* tp_iternext */ module_methods, /* tp_methods */ module_members, /* tp_members */ - 0, /* tp_getset */ + module_getsets, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ diff --git a/contrib/tools/python3/src/Objects/object.c b/contrib/tools/python3/src/Objects/object.c index 623ee52eb1..47c352e3d6 100644 --- a/contrib/tools/python3/src/Objects/object.c +++ b/contrib/tools/python3/src/Objects/object.c @@ -10,9 +10,16 @@ #include "pycore_pylifecycle.h" #include "pycore_pymem.h" // _PyMem_IsPtrFreed() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_symtable.h" // PySTEntry_Type +#include "pycore_unionobject.h" // _PyUnion_Type #include "frameobject.h" #include "interpreteridobject.h" +#ifdef Py_LIMITED_API + // Prevent recursive call _Py_IncRef() <=> Py_INCREF() +# error "Py_LIMITED_API macro must not be defined" +#endif + #ifdef __cplusplus extern "C" { #endif @@ -66,8 +73,7 @@ _Py_GetRefTotal(void) void _PyDebug_PrintTotalRefs(void) { fprintf(stderr, - "[%" PY_FORMAT_SIZE_T "d refs, " - "%" PY_FORMAT_SIZE_T "d blocks]\n", + "[%zd refs, %zd blocks]\n", _Py_GetRefTotal(), _Py_GetAllocatedBlocks()); } #endif /* Py_REF_DEBUG */ @@ -137,36 +143,48 @@ Py_DecRef(PyObject *o) Py_XDECREF(o); } +void +_Py_IncRef(PyObject *o) +{ + Py_INCREF(o); +} + +void +_Py_DecRef(PyObject *o) +{ + Py_DECREF(o); +} + PyObject * PyObject_Init(PyObject *op, PyTypeObject *tp) { - /* Any changes should be reflected in PyObject_INIT() macro */ if (op == NULL) { return PyErr_NoMemory(); } - return PyObject_INIT(op, tp); + _PyObject_Init(op, tp); + return op; } PyVarObject * PyObject_InitVar(PyVarObject *op, PyTypeObject *tp, Py_ssize_t size) { - /* Any changes should be reflected in PyObject_INIT_VAR() macro */ if (op == NULL) { return (PyVarObject *) PyErr_NoMemory(); } - return PyObject_INIT_VAR(op, tp, size); + _PyObject_InitVar(op, tp, size); + return op; } PyObject * _PyObject_New(PyTypeObject *tp) { - PyObject *op = (PyObject *) PyObject_MALLOC(_PyObject_SIZE(tp)); + PyObject *op = (PyObject *) PyObject_Malloc(_PyObject_SIZE(tp)); if (op == NULL) { return PyErr_NoMemory(); } - PyObject_INIT(op, tp); + _PyObject_Init(op, tp); return op; } @@ -175,10 +193,12 @@ _PyObject_NewVar(PyTypeObject *tp, Py_ssize_t nitems) { PyVarObject *op; const size_t size = _PyObject_VAR_SIZE(tp, nitems); - op = (PyVarObject *) PyObject_MALLOC(size); - if (op == NULL) + op = (PyVarObject *) PyObject_Malloc(size); + if (op == NULL) { return (PyVarObject *)PyErr_NoMemory(); - return PyObject_INIT_VAR(op, tp, nitems); + } + _PyObject_InitVar(op, tp, nitems); + return op; } void @@ -854,50 +874,80 @@ _PyObject_GetAttrId(PyObject *v, _Py_Identifier *name) } int -_PyObject_HasAttrId(PyObject *v, _Py_Identifier *name) +_PyObject_SetAttrId(PyObject *v, _Py_Identifier *name, PyObject *w) { int result; PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ if (!oname) return -1; - result = PyObject_HasAttr(v, oname); + result = PyObject_SetAttr(v, oname, w); return result; } -int -_PyObject_SetAttrId(PyObject *v, _Py_Identifier *name, PyObject *w) +static inline int +set_attribute_error_context(PyObject* v, PyObject* name) { - int result; - PyObject *oname = _PyUnicode_FromId(name); /* borrowed */ - if (!oname) - return -1; - result = PyObject_SetAttr(v, oname, w); - return result; + assert(PyErr_Occurred()); + _Py_IDENTIFIER(name); + _Py_IDENTIFIER(obj); + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) { + return 0; + } + // Intercept AttributeError exceptions and augment them to offer suggestions later. + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + PyErr_NormalizeException(&type, &value, &traceback); + // Check if the normalized exception is indeed an AttributeError + if (!PyErr_GivenExceptionMatches(value, PyExc_AttributeError)) { + goto restore; + } + PyAttributeErrorObject* the_exc = (PyAttributeErrorObject*) value; + // Check if this exception was already augmented + if (the_exc->name || the_exc->obj) { + goto restore; + } + // Augment the exception with the name and object + if (_PyObject_SetAttrId(value, &PyId_name, name) || + _PyObject_SetAttrId(value, &PyId_obj, v)) { + return 1; + } +restore: + PyErr_Restore(type, value, traceback); + return 0; } PyObject * PyObject_GetAttr(PyObject *v, PyObject *name) { PyTypeObject *tp = Py_TYPE(v); - if (!PyUnicode_Check(name)) { PyErr_Format(PyExc_TypeError, "attribute name must be string, not '%.200s'", Py_TYPE(name)->tp_name); return NULL; } - if (tp->tp_getattro != NULL) - return (*tp->tp_getattro)(v, name); - if (tp->tp_getattr != NULL) { + + PyObject* result = NULL; + if (tp->tp_getattro != NULL) { + result = (*tp->tp_getattro)(v, name); + } + else if (tp->tp_getattr != NULL) { const char *name_str = PyUnicode_AsUTF8(name); - if (name_str == NULL) + if (name_str == NULL) { return NULL; - return (*tp->tp_getattr)(v, (char *)name_str); + } + result = (*tp->tp_getattr)(v, (char *)name_str); } - PyErr_Format(PyExc_AttributeError, - "'%.50s' object has no attribute '%U'", - tp->tp_name, name); - return NULL; + else { + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%U'", + tp->tp_name, name); + } + + if (result == NULL) { + set_attribute_error_context(v, name); + } + return result; } int @@ -1156,6 +1206,8 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%U'", tp->tp_name, name); + + set_attribute_error_context(obj, name); return 0; } @@ -1168,7 +1220,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, /* Make sure the logic of _PyObject_GetMethod is in sync with this method. - When suppress=1, this function suppress AttributeError. + When suppress=1, this function suppresses AttributeError. */ PyTypeObject *tp = Py_TYPE(obj); @@ -1386,7 +1438,7 @@ PyObject_GenericSetDict(PyObject *obj, PyObject *value, void *context) } -/* Test a value used as condition, e.g., in a for or if statement. +/* Test a value used as condition, e.g., in a while or if statement. Return -1 if an error occurred */ int @@ -1738,82 +1790,109 @@ _PyTypes_Init(void) return status; } -#define INIT_TYPE(TYPE, NAME) \ +#define INIT_TYPE(TYPE) \ do { \ - if (PyType_Ready(TYPE) < 0) { \ - return _PyStatus_ERR("Can't initialize " NAME " type"); \ + if (PyType_Ready(&(TYPE)) < 0) { \ + return _PyStatus_ERR("Can't initialize " #TYPE " type"); \ } \ } while (0) - INIT_TYPE(&PyBaseObject_Type, "object"); - INIT_TYPE(&PyType_Type, "type"); - INIT_TYPE(&_PyWeakref_RefType, "weakref"); - INIT_TYPE(&_PyWeakref_CallableProxyType, "callable weakref proxy"); - INIT_TYPE(&_PyWeakref_ProxyType, "weakref proxy"); - INIT_TYPE(&PyLong_Type, "int"); - INIT_TYPE(&PyBool_Type, "bool"); - INIT_TYPE(&PyByteArray_Type, "bytearray"); - INIT_TYPE(&PyBytes_Type, "str"); - INIT_TYPE(&PyList_Type, "list"); - INIT_TYPE(&_PyNone_Type, "None"); - INIT_TYPE(&_PyNotImplemented_Type, "NotImplemented"); - INIT_TYPE(&PyTraceBack_Type, "traceback"); - INIT_TYPE(&PySuper_Type, "super"); - INIT_TYPE(&PyRange_Type, "range"); - INIT_TYPE(&PyDict_Type, "dict"); - INIT_TYPE(&PyDictKeys_Type, "dict keys"); - INIT_TYPE(&PyDictValues_Type, "dict values"); - INIT_TYPE(&PyDictItems_Type, "dict items"); - INIT_TYPE(&PyDictRevIterKey_Type, "reversed dict keys"); - INIT_TYPE(&PyDictRevIterValue_Type, "reversed dict values"); - INIT_TYPE(&PyDictRevIterItem_Type, "reversed dict items"); - INIT_TYPE(&PyODict_Type, "OrderedDict"); - INIT_TYPE(&PyODictKeys_Type, "odict_keys"); - INIT_TYPE(&PyODictItems_Type, "odict_items"); - INIT_TYPE(&PyODictValues_Type, "odict_values"); - INIT_TYPE(&PyODictIter_Type, "odict_keyiterator"); - INIT_TYPE(&PySet_Type, "set"); - INIT_TYPE(&PyUnicode_Type, "str"); - INIT_TYPE(&PySlice_Type, "slice"); - INIT_TYPE(&PyStaticMethod_Type, "static method"); - INIT_TYPE(&PyComplex_Type, "complex"); - INIT_TYPE(&PyFloat_Type, "float"); - INIT_TYPE(&PyFrozenSet_Type, "frozenset"); - INIT_TYPE(&PyProperty_Type, "property"); - INIT_TYPE(&_PyManagedBuffer_Type, "managed buffer"); - INIT_TYPE(&PyMemoryView_Type, "memoryview"); - INIT_TYPE(&PyTuple_Type, "tuple"); - INIT_TYPE(&PyEnum_Type, "enumerate"); - INIT_TYPE(&PyReversed_Type, "reversed"); - INIT_TYPE(&PyStdPrinter_Type, "StdPrinter"); - INIT_TYPE(&PyCode_Type, "code"); - INIT_TYPE(&PyFrame_Type, "frame"); - INIT_TYPE(&PyCFunction_Type, "builtin function"); - INIT_TYPE(&PyCMethod_Type, "builtin method"); - INIT_TYPE(&PyMethod_Type, "method"); - INIT_TYPE(&PyFunction_Type, "function"); - INIT_TYPE(&PyDictProxy_Type, "dict proxy"); - INIT_TYPE(&PyGen_Type, "generator"); - INIT_TYPE(&PyGetSetDescr_Type, "get-set descriptor"); - INIT_TYPE(&PyWrapperDescr_Type, "wrapper"); - INIT_TYPE(&_PyMethodWrapper_Type, "method wrapper"); - INIT_TYPE(&PyEllipsis_Type, "ellipsis"); - INIT_TYPE(&PyMemberDescr_Type, "member descriptor"); - INIT_TYPE(&_PyNamespace_Type, "namespace"); - INIT_TYPE(&PyCapsule_Type, "capsule"); - INIT_TYPE(&PyLongRangeIter_Type, "long range iterator"); - INIT_TYPE(&PyCell_Type, "cell"); - INIT_TYPE(&PyInstanceMethod_Type, "instance method"); - INIT_TYPE(&PyClassMethodDescr_Type, "class method descr"); - INIT_TYPE(&PyMethodDescr_Type, "method descr"); - INIT_TYPE(&PyCallIter_Type, "call iter"); - INIT_TYPE(&PySeqIter_Type, "sequence iterator"); - INIT_TYPE(&PyPickleBuffer_Type, "pickle.PickleBuffer"); - INIT_TYPE(&PyCoro_Type, "coroutine"); - INIT_TYPE(&_PyCoroWrapper_Type, "coroutine wrapper"); - INIT_TYPE(&_PyInterpreterID_Type, "interpreter ID"); - return _PyStatus_OK(); + // Base types + INIT_TYPE(PyBaseObject_Type); + INIT_TYPE(PyType_Type); + assert(PyBaseObject_Type.tp_base == NULL); + assert(PyType_Type.tp_base == &PyBaseObject_Type); + + // All other static types + INIT_TYPE(PyAsyncGen_Type); + INIT_TYPE(PyBool_Type); + INIT_TYPE(PyByteArrayIter_Type); + INIT_TYPE(PyByteArray_Type); + INIT_TYPE(PyBytesIter_Type); + INIT_TYPE(PyBytes_Type); + INIT_TYPE(PyCFunction_Type); + INIT_TYPE(PyCMethod_Type); + INIT_TYPE(PyCallIter_Type); + INIT_TYPE(PyCapsule_Type); + INIT_TYPE(PyCell_Type); + INIT_TYPE(PyClassMethodDescr_Type); + INIT_TYPE(PyClassMethod_Type); + INIT_TYPE(PyCode_Type); + INIT_TYPE(PyComplex_Type); + INIT_TYPE(PyCoro_Type); + INIT_TYPE(PyDictItems_Type); + INIT_TYPE(PyDictIterItem_Type); + INIT_TYPE(PyDictIterKey_Type); + INIT_TYPE(PyDictIterValue_Type); + INIT_TYPE(PyDictKeys_Type); + INIT_TYPE(PyDictProxy_Type); + INIT_TYPE(PyDictRevIterItem_Type); + INIT_TYPE(PyDictRevIterKey_Type); + INIT_TYPE(PyDictRevIterValue_Type); + INIT_TYPE(PyDictValues_Type); + INIT_TYPE(PyDict_Type); + INIT_TYPE(PyEllipsis_Type); + INIT_TYPE(PyEnum_Type); + INIT_TYPE(PyFloat_Type); + INIT_TYPE(PyFrame_Type); + INIT_TYPE(PyFrozenSet_Type); + INIT_TYPE(PyFunction_Type); + INIT_TYPE(PyGen_Type); + INIT_TYPE(PyGetSetDescr_Type); + INIT_TYPE(PyInstanceMethod_Type); + INIT_TYPE(PyListIter_Type); + INIT_TYPE(PyListRevIter_Type); + INIT_TYPE(PyList_Type); + INIT_TYPE(PyLongRangeIter_Type); + INIT_TYPE(PyLong_Type); + INIT_TYPE(PyMemberDescr_Type); + INIT_TYPE(PyMemoryView_Type); + INIT_TYPE(PyMethodDescr_Type); + INIT_TYPE(PyMethod_Type); + INIT_TYPE(PyModuleDef_Type); + INIT_TYPE(PyModule_Type); + INIT_TYPE(PyODictItems_Type); + INIT_TYPE(PyODictIter_Type); + INIT_TYPE(PyODictKeys_Type); + INIT_TYPE(PyODictValues_Type); + INIT_TYPE(PyODict_Type); + INIT_TYPE(PyPickleBuffer_Type); + INIT_TYPE(PyProperty_Type); + INIT_TYPE(PyRangeIter_Type); + INIT_TYPE(PyRange_Type); + INIT_TYPE(PyReversed_Type); + INIT_TYPE(PySTEntry_Type); + INIT_TYPE(PySeqIter_Type); + INIT_TYPE(PySetIter_Type); + INIT_TYPE(PySet_Type); + INIT_TYPE(PySlice_Type); + INIT_TYPE(PyStaticMethod_Type); + INIT_TYPE(PyStdPrinter_Type); + INIT_TYPE(PySuper_Type); + INIT_TYPE(PyTraceBack_Type); + INIT_TYPE(PyTupleIter_Type); + INIT_TYPE(PyTuple_Type); + INIT_TYPE(PyUnicodeIter_Type); + INIT_TYPE(PyUnicode_Type); + INIT_TYPE(PyWrapperDescr_Type); + INIT_TYPE(Py_GenericAliasType); + INIT_TYPE(_PyAnextAwaitable_Type); + INIT_TYPE(_PyAsyncGenASend_Type); + INIT_TYPE(_PyAsyncGenAThrow_Type); + INIT_TYPE(_PyAsyncGenWrappedValue_Type); + INIT_TYPE(_PyCoroWrapper_Type); + INIT_TYPE(_PyInterpreterID_Type); + INIT_TYPE(_PyManagedBuffer_Type); + INIT_TYPE(_PyMethodWrapper_Type); + INIT_TYPE(_PyNamespace_Type); + INIT_TYPE(_PyNone_Type); + INIT_TYPE(_PyNotImplemented_Type); + INIT_TYPE(_PyWeakref_CallableProxyType); + INIT_TYPE(_PyWeakref_ProxyType); + INIT_TYPE(_PyWeakref_RefType); + INIT_TYPE(_PyUnion_Type); + return _PyStatus_OK(); #undef INIT_TYPE } @@ -1876,9 +1955,10 @@ _Py_PrintReferences(FILE *fp) PyObject *op; fprintf(fp, "Remaining objects:\n"); for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) { - fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] ", (void *)op, Py_REFCNT(op)); - if (PyObject_Print(op, fp, 0) != 0) + fprintf(fp, "%p [%zd] ", (void *)op, Py_REFCNT(op)); + if (PyObject_Print(op, fp, 0) != 0) { PyErr_Clear(); + } putc('\n', fp); } } @@ -1892,7 +1972,7 @@ _Py_PrintReferenceAddresses(FILE *fp) PyObject *op; fprintf(fp, "Remaining object addresses:\n"); for (op = refchain._ob_next; op != &refchain; op = op->_ob_next) - fprintf(fp, "%p [%" PY_FORMAT_SIZE_T "d] %s\n", (void *)op, + fprintf(fp, "%p [%zd] %s\n", (void *)op, Py_REFCNT(op), Py_TYPE(op)->tp_name); } @@ -2029,8 +2109,8 @@ finally: void _PyTrash_deposit_object(PyObject *op) { - PyThreadState *tstate = _PyThreadState_GET(); - struct _gc_runtime_state *gcstate = &tstate->interp->gc; + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _gc_runtime_state *gcstate = &interp->gc; _PyObject_ASSERT(op, _PyObject_IS_GC(op)); _PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op)); @@ -2057,8 +2137,8 @@ _PyTrash_thread_deposit_object(PyObject *op) void _PyTrash_destroy_chain(void) { - PyThreadState *tstate = _PyThreadState_GET(); - struct _gc_runtime_state *gcstate = &tstate->interp->gc; + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _gc_runtime_state *gcstate = &interp->gc; while (gcstate->trash_delete_later) { PyObject *op = gcstate->trash_delete_later; @@ -2143,6 +2223,15 @@ _PyTrash_end(PyThreadState *tstate) } +/* bpo-40170: It's only be used in Py_TRASHCAN_BEGIN macro to hide + implementation details. */ +int +_PyTrash_cond(PyObject *op, destructor dealloc) +{ + return Py_TYPE(op)->tp_dealloc == dealloc; +} + + void _Py_NO_RETURN _PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg, const char *file, int line, const char *function) @@ -2217,6 +2306,49 @@ PyObject_GET_WEAKREFS_LISTPTR(PyObject *op) } +#undef Py_NewRef +#undef Py_XNewRef + +// Export Py_NewRef() and Py_XNewRef() as regular functions for the stable ABI. +PyObject* +Py_NewRef(PyObject *obj) +{ + return _Py_NewRef(obj); +} + +PyObject* +Py_XNewRef(PyObject *obj) +{ + return _Py_XNewRef(obj); +} + +#undef Py_Is +#undef Py_IsNone +#undef Py_IsTrue +#undef Py_IsFalse + +// Export Py_Is(), Py_IsNone(), Py_IsTrue(), Py_IsFalse() as regular functions +// for the stable ABI. +int Py_Is(PyObject *x, PyObject *y) +{ + return (x == y); +} + +int Py_IsNone(PyObject *x) +{ + return Py_Is(x, Py_None); +} + +int Py_IsTrue(PyObject *x) +{ + return Py_Is(x, Py_True); +} + +int Py_IsFalse(PyObject *x) +{ + return Py_Is(x, Py_False); +} + #ifdef __cplusplus } #endif diff --git a/contrib/tools/python3/src/Objects/obmalloc.c b/contrib/tools/python3/src/Objects/obmalloc.c index 9f8e0d114f..615703a963 100644 --- a/contrib/tools/python3/src/Objects/obmalloc.c +++ b/contrib/tools/python3/src/Objects/obmalloc.c @@ -894,6 +894,22 @@ static int running_on_valgrind = -1; #endif #endif +#if !defined(WITH_PYMALLOC_RADIX_TREE) +/* Use radix-tree to track arena memory regions, for address_in_range(). + * Enable by default since it allows larger pool sizes. Can be disabled + * using -DWITH_PYMALLOC_RADIX_TREE=0 */ +#define WITH_PYMALLOC_RADIX_TREE 1 +#endif + +#if SIZEOF_VOID_P > 4 +/* on 64-bit platforms use larger pools and arenas if we can */ +#define USE_LARGE_ARENAS +#if WITH_PYMALLOC_RADIX_TREE +/* large pools only supported if radix-tree is enabled */ +#define USE_LARGE_POOLS +#endif +#endif + /* * The allocator sub-allocates <Big> blocks of memory (called arenas) aligned * on a page boundary. This is a reserved virtual address space for the @@ -907,18 +923,34 @@ static int running_on_valgrind = -1; * Arenas are allocated with mmap() on systems supporting anonymous memory * mappings to reduce heap fragmentation. */ -#define ARENA_SIZE (256 << 10) /* 256KB */ +#ifdef USE_LARGE_ARENAS +#define ARENA_BITS 20 /* 1 MiB */ +#else +#define ARENA_BITS 18 /* 256 KiB */ +#endif +#define ARENA_SIZE (1 << ARENA_BITS) +#define ARENA_SIZE_MASK (ARENA_SIZE - 1) #ifdef WITH_MEMORY_LIMITS #define MAX_ARENAS (SMALL_MEMORY_LIMIT / ARENA_SIZE) #endif /* - * Size of the pools used for small blocks. Should be a power of 2, - * between 1K and SYSTEM_PAGE_SIZE, that is: 1k, 2k, 4k. + * Size of the pools used for small blocks. Must be a power of 2. */ -#define POOL_SIZE SYSTEM_PAGE_SIZE /* must be 2^N */ -#define POOL_SIZE_MASK SYSTEM_PAGE_SIZE_MASK +#ifdef USE_LARGE_POOLS +#define POOL_BITS 14 /* 16 KiB */ +#else +#define POOL_BITS 12 /* 4 KiB */ +#endif +#define POOL_SIZE (1 << POOL_BITS) +#define POOL_SIZE_MASK (POOL_SIZE - 1) + +#if !WITH_PYMALLOC_RADIX_TREE +#if POOL_SIZE != SYSTEM_PAGE_SIZE +# error "pool size must be equal to system page size" +#endif +#endif #define MAX_POOLS_IN_ARENA (ARENA_SIZE / POOL_SIZE) #if MAX_POOLS_IN_ARENA * POOL_SIZE != ARENA_SIZE @@ -1233,6 +1265,264 @@ _Py_GetAllocatedBlocks(void) return n; } +#if WITH_PYMALLOC_RADIX_TREE +/*==========================================================================*/ +/* radix tree for tracking arena usage + + bit allocation for keys + + 64-bit pointers and 2^20 arena size: + 16 -> ignored (POINTER_BITS - ADDRESS_BITS) + 10 -> MAP_TOP + 10 -> MAP_MID + 8 -> MAP_BOT + 20 -> ideal aligned arena + ---- + 64 + + 32-bit pointers and 2^18 arena size: + 14 -> MAP_BOT + 18 -> ideal aligned arena + ---- + 32 + +*/ + +#if SIZEOF_VOID_P == 8 + +/* number of bits in a pointer */ +#define POINTER_BITS 64 + +/* Current 64-bit processors are limited to 48-bit physical addresses. For + * now, the top 17 bits of addresses will all be equal to bit 2**47. If that + * changes in the future, this must be adjusted upwards. + */ +#define ADDRESS_BITS 48 + +/* use the top and mid layers of the radix tree */ +#define USE_INTERIOR_NODES + +#elif SIZEOF_VOID_P == 4 + +#define POINTER_BITS 32 +#define ADDRESS_BITS 32 + +#else + + /* Currently this code works for 64-bit or 32-bit pointers only. */ +#error "obmalloc radix tree requires 64-bit or 32-bit pointers." + +#endif /* SIZEOF_VOID_P */ + +/* arena_coverage_t members require this to be true */ +#if ARENA_BITS >= 32 +# error "arena size must be < 2^32" +#endif + +#ifdef USE_INTERIOR_NODES +/* number of bits used for MAP_TOP and MAP_MID nodes */ +#define INTERIOR_BITS ((ADDRESS_BITS - ARENA_BITS + 2) / 3) +#else +#define INTERIOR_BITS 0 +#endif + +#define MAP_TOP_BITS INTERIOR_BITS +#define MAP_TOP_LENGTH (1 << MAP_TOP_BITS) +#define MAP_TOP_MASK (MAP_TOP_LENGTH - 1) + +#define MAP_MID_BITS INTERIOR_BITS +#define MAP_MID_LENGTH (1 << MAP_MID_BITS) +#define MAP_MID_MASK (MAP_MID_LENGTH - 1) + +#define MAP_BOT_BITS (ADDRESS_BITS - ARENA_BITS - 2*INTERIOR_BITS) +#define MAP_BOT_LENGTH (1 << MAP_BOT_BITS) +#define MAP_BOT_MASK (MAP_BOT_LENGTH - 1) + +#define MAP_BOT_SHIFT ARENA_BITS +#define MAP_MID_SHIFT (MAP_BOT_BITS + MAP_BOT_SHIFT) +#define MAP_TOP_SHIFT (MAP_MID_BITS + MAP_MID_SHIFT) + +#define AS_UINT(p) ((uintptr_t)(p)) +#define MAP_BOT_INDEX(p) ((AS_UINT(p) >> MAP_BOT_SHIFT) & MAP_BOT_MASK) +#define MAP_MID_INDEX(p) ((AS_UINT(p) >> MAP_MID_SHIFT) & MAP_MID_MASK) +#define MAP_TOP_INDEX(p) ((AS_UINT(p) >> MAP_TOP_SHIFT) & MAP_TOP_MASK) + +#if ADDRESS_BITS > POINTER_BITS +/* Return non-physical address bits of a pointer. Those bits should be same + * for all valid pointers if ADDRESS_BITS set correctly. Linux has support for + * 57-bit address space (Intel 5-level paging) but will not currently give + * those addresses to user space. + */ +#define HIGH_BITS(p) (AS_UINT(p) >> ADDRESS_BITS) +#else +#define HIGH_BITS(p) 0 +#endif + + +/* This is the leaf of the radix tree. See arena_map_mark_used() for the + * meaning of these members. */ +typedef struct { + int32_t tail_hi; + int32_t tail_lo; +} arena_coverage_t; + +typedef struct arena_map_bot { + /* The members tail_hi and tail_lo are accessed together. So, it + * better to have them as an array of structs, rather than two + * arrays. + */ + arena_coverage_t arenas[MAP_BOT_LENGTH]; +} arena_map_bot_t; + +#ifdef USE_INTERIOR_NODES +typedef struct arena_map_mid { + struct arena_map_bot *ptrs[MAP_MID_LENGTH]; +} arena_map_mid_t; + +typedef struct arena_map_top { + struct arena_map_mid *ptrs[MAP_TOP_LENGTH]; +} arena_map_top_t; +#endif + +/* The root of radix tree. Note that by initializing like this, the memory + * should be in the BSS. The OS will only memory map pages as the MAP_MID + * nodes get used (OS pages are demand loaded as needed). + */ +#ifdef USE_INTERIOR_NODES +static arena_map_top_t arena_map_root; +/* accounting for number of used interior nodes */ +static int arena_map_mid_count; +static int arena_map_bot_count; +#else +static arena_map_bot_t arena_map_root; +#endif + +/* Return a pointer to a bottom tree node, return NULL if it doesn't exist or + * it cannot be created */ +static arena_map_bot_t * +arena_map_get(block *p, int create) +{ +#ifdef USE_INTERIOR_NODES + /* sanity check that ADDRESS_BITS is correct */ + assert(HIGH_BITS(p) == HIGH_BITS(&arena_map_root)); + int i1 = MAP_TOP_INDEX(p); + if (arena_map_root.ptrs[i1] == NULL) { + if (!create) { + return NULL; + } + arena_map_mid_t *n = PyMem_RawCalloc(1, sizeof(arena_map_mid_t)); + if (n == NULL) { + return NULL; + } + arena_map_root.ptrs[i1] = n; + arena_map_mid_count++; + } + int i2 = MAP_MID_INDEX(p); + if (arena_map_root.ptrs[i1]->ptrs[i2] == NULL) { + if (!create) { + return NULL; + } + arena_map_bot_t *n = PyMem_RawCalloc(1, sizeof(arena_map_bot_t)); + if (n == NULL) { + return NULL; + } + arena_map_root.ptrs[i1]->ptrs[i2] = n; + arena_map_bot_count++; + } + return arena_map_root.ptrs[i1]->ptrs[i2]; +#else + return &arena_map_root; +#endif +} + + +/* The radix tree only tracks arenas. So, for 16 MiB arenas, we throw + * away 24 bits of the address. That reduces the space requirement of + * the tree compared to similar radix tree page-map schemes. In + * exchange for slashing the space requirement, it needs more + * computation to check an address. + * + * Tracking coverage is done by "ideal" arena address. It is easier to + * explain in decimal so let's say that the arena size is 100 bytes. + * Then, ideal addresses are 100, 200, 300, etc. For checking if a + * pointer address is inside an actual arena, we have to check two ideal + * arena addresses. E.g. if pointer is 357, we need to check 200 and + * 300. In the rare case that an arena is aligned in the ideal way + * (e.g. base address of arena is 200) then we only have to check one + * ideal address. + * + * The tree nodes for 200 and 300 both store the address of arena. + * There are two cases: the arena starts at a lower ideal arena and + * extends to this one, or the arena starts in this arena and extends to + * the next ideal arena. The tail_lo and tail_hi members correspond to + * these two cases. + */ + + +/* mark or unmark addresses covered by arena */ +static int +arena_map_mark_used(uintptr_t arena_base, int is_used) +{ + /* sanity check that ADDRESS_BITS is correct */ + assert(HIGH_BITS(arena_base) == HIGH_BITS(&arena_map_root)); + arena_map_bot_t *n_hi = arena_map_get((block *)arena_base, is_used); + if (n_hi == NULL) { + assert(is_used); /* otherwise node should already exist */ + return 0; /* failed to allocate space for node */ + } + int i3 = MAP_BOT_INDEX((block *)arena_base); + int32_t tail = (int32_t)(arena_base & ARENA_SIZE_MASK); + if (tail == 0) { + /* is ideal arena address */ + n_hi->arenas[i3].tail_hi = is_used ? -1 : 0; + } + else { + /* arena_base address is not ideal (aligned to arena size) and + * so it potentially covers two MAP_BOT nodes. Get the MAP_BOT node + * for the next arena. Note that it might be in different MAP_TOP + * and MAP_MID nodes as well so we need to call arena_map_get() + * again (do the full tree traversal). + */ + n_hi->arenas[i3].tail_hi = is_used ? tail : 0; + uintptr_t arena_base_next = arena_base + ARENA_SIZE; + /* If arena_base is a legit arena address, so is arena_base_next - 1 + * (last address in arena). If arena_base_next overflows then it + * must overflow to 0. However, that would mean arena_base was + * "ideal" and we should not be in this case. */ + assert(arena_base < arena_base_next); + arena_map_bot_t *n_lo = arena_map_get((block *)arena_base_next, is_used); + if (n_lo == NULL) { + assert(is_used); /* otherwise should already exist */ + n_hi->arenas[i3].tail_hi = 0; + return 0; /* failed to allocate space for node */ + } + int i3_next = MAP_BOT_INDEX(arena_base_next); + n_lo->arenas[i3_next].tail_lo = is_used ? tail : 0; + } + return 1; +} + +/* Return true if 'p' is a pointer inside an obmalloc arena. + * _PyObject_Free() calls this so it needs to be very fast. */ +static int +arena_map_is_used(block *p) +{ + arena_map_bot_t *n = arena_map_get(p, 0); + if (n == NULL) { + return 0; + } + int i3 = MAP_BOT_INDEX(p); + /* ARENA_BITS must be < 32 so that the tail is a non-negative int32_t. */ + int32_t hi = n->arenas[i3].tail_hi; + int32_t lo = n->arenas[i3].tail_lo; + int32_t tail = (int32_t)(AS_UINT(p) & ARENA_SIZE_MASK); + return (tail < lo) || (tail >= hi && hi != 0); +} + +/* end of radix tree logic */ +/*==========================================================================*/ +#endif /* WITH_PYMALLOC_RADIX_TREE */ + /* Allocate a new arena. If we run out of memory, return NULL. Else * allocate a new arena, and return the address of an arena_object @@ -1302,6 +1592,15 @@ new_arena(void) unused_arena_objects = arenaobj->nextarena; assert(arenaobj->address == 0); address = _PyObject_Arena.alloc(_PyObject_Arena.ctx, ARENA_SIZE); +#if WITH_PYMALLOC_RADIX_TREE + if (address != NULL) { + if (!arena_map_mark_used((uintptr_t)address, 1)) { + /* marking arena in radix tree failed, abort */ + _PyObject_Arena.free(_PyObject_Arena.ctx, address, ARENA_SIZE); + address = NULL; + } + } +#endif if (address == NULL) { /* The allocation failed: return NULL after putting the * arenaobj back. @@ -1332,6 +1631,17 @@ new_arena(void) } + +#if WITH_PYMALLOC_RADIX_TREE +/* Return true if and only if P is an address that was allocated by + pymalloc. When the radix tree is used, 'poolp' is unused. + */ +static bool +address_in_range(void *p, poolp pool) +{ + return arena_map_is_used(p); +} +#else /* address_in_range(P, POOL) @@ -1423,6 +1733,7 @@ address_in_range(void *p, poolp pool) arenas[arenaindex].address != 0; } +#endif /* !WITH_PYMALLOC_RADIX_TREE */ /*==========================================================================*/ @@ -1768,6 +2079,11 @@ insert_to_freepool(poolp pool) ao->nextarena = unused_arena_objects; unused_arena_objects = ao; +#if WITH_PYMALLOC_RADIX_TREE + /* mark arena region as not under control of obmalloc */ + arena_map_mark_used(ao->address, 0); +#endif + /* Free the entire arena. */ _PyObject_Arena.free(_PyObject_Arena.ctx, (void *)ao->address, ARENA_SIZE); @@ -2420,8 +2736,7 @@ _PyObject_DebugDumpAddress(const void *p) fprintf(stderr, " API '%c'\n", id); nbytes = read_size_t(q - 2*SST); - fprintf(stderr, " %" PY_FORMAT_SIZE_T "u bytes originally " - "requested\n", nbytes); + fprintf(stderr, " %zu bytes originally requested\n", nbytes); /* In case this is nuts, check the leading pad bytes first. */ fprintf(stderr, " The %d pad bytes at p-%d are ", SST-1, SST-1); @@ -2477,8 +2792,9 @@ _PyObject_DebugDumpAddress(const void *p) #ifdef PYMEM_DEBUG_SERIALNO size_t serial = read_size_t(tail + SST); - fprintf(stderr, " The block was made by call #%" PY_FORMAT_SIZE_T - "u to debug malloc/realloc.\n", serial); + fprintf(stderr, + " The block was made by call #%zu to debug malloc/realloc.\n", + serial); #endif if (nbytes > 0) { @@ -2553,7 +2869,7 @@ _PyDebugAllocatorStats(FILE *out, char buf1[128]; char buf2[128]; PyOS_snprintf(buf1, sizeof(buf1), - "%d %ss * %" PY_FORMAT_SIZE_T "d bytes each", + "%d %ss * %zd bytes each", num_blocks, block_name, sizeof_block); PyOS_snprintf(buf2, sizeof(buf2), "%48s ", buf1); @@ -2694,10 +3010,7 @@ _PyObject_DebugMallocStats(FILE *out) assert(b == 0 && f == 0); continue; } - fprintf(out, "%5u %6u " - "%11" PY_FORMAT_SIZE_T "u " - "%15" PY_FORMAT_SIZE_T "u " - "%13" PY_FORMAT_SIZE_T "u\n", + fprintf(out, "%5u %6u %11zu %15zu %13zu\n", i, size, p, b, f); allocated_bytes += b * size; available_bytes += f * size; @@ -2716,12 +3029,13 @@ _PyObject_DebugMallocStats(FILE *out) (void)printone(out, "# arenas allocated current", narenas); PyOS_snprintf(buf, sizeof(buf), - "%" PY_FORMAT_SIZE_T "u arenas * %d bytes/arena", - narenas, ARENA_SIZE); + "%zu arenas * %d bytes/arena", + narenas, ARENA_SIZE); (void)printone(out, buf, narenas * ARENA_SIZE); fputc('\n', out); + /* Account for what all of those arena bytes are being used for. */ total = printone(out, "# bytes in allocated blocks", allocated_bytes); total += printone(out, "# bytes in available blocks", available_bytes); @@ -2733,6 +3047,25 @@ _PyObject_DebugMallocStats(FILE *out) total += printone(out, "# bytes lost to quantization", quantization); total += printone(out, "# bytes lost to arena alignment", arena_alignment); (void)printone(out, "Total", total); + assert(narenas * ARENA_SIZE == total); + +#if WITH_PYMALLOC_RADIX_TREE + fputs("\narena map counts\n", out); +#ifdef USE_INTERIOR_NODES + (void)printone(out, "# arena map mid nodes", arena_map_mid_count); + (void)printone(out, "# arena map bot nodes", arena_map_bot_count); + fputc('\n', out); +#endif + total = printone(out, "# bytes lost to arena map root", sizeof(arena_map_root)); +#ifdef USE_INTERIOR_NODES + total += printone(out, "# bytes lost to arena map mid", + sizeof(arena_map_mid_t) * arena_map_mid_count); + total += printone(out, "# bytes lost to arena map bot", + sizeof(arena_map_bot_t) * arena_map_bot_count); + (void)printone(out, "Total", total); +#endif +#endif + return 1; } diff --git a/contrib/tools/python3/src/Objects/odictobject.c b/contrib/tools/python3/src/Objects/odictobject.c index f3980aba93..c0ccb16bc3 100644 --- a/contrib/tools/python3/src/Objects/odictobject.c +++ b/contrib/tools/python3/src/Objects/odictobject.c @@ -459,7 +459,7 @@ later: - implement a fuller MutableMapping API in C? - move the MutableMapping implementation to abstract.c? - optimize mutablemapping_update -- use PyObject_MALLOC (small object allocator) for odict nodes? +- use PyObject_Malloc (small object allocator) for odict nodes? - support subclasses better (e.g. in odict_richcompare) */ @@ -567,14 +567,14 @@ _odict_resize(PyODictObject *od) i = _odict_get_index_raw(od, _odictnode_KEY(node), _odictnode_HASH(node)); if (i < 0) { - PyMem_FREE(fast_nodes); + PyMem_Free(fast_nodes); return -1; } fast_nodes[i] = node; } /* Replace the old fast nodes table. */ - PyMem_FREE(od->od_fast_nodes); + PyMem_Free(od->od_fast_nodes); od->od_fast_nodes = fast_nodes; od->od_fast_nodes_size = size; od->od_resize_sentinel = ((PyDictObject *)od)->ma_keys; @@ -683,7 +683,7 @@ _odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash) } /* must not be added yet */ - node = (_ODictNode *)PyMem_MALLOC(sizeof(_ODictNode)); + node = (_ODictNode *)PyMem_Malloc(sizeof(_ODictNode)); if (node == NULL) { Py_DECREF(key); PyErr_NoMemory(); @@ -701,7 +701,7 @@ _odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash) #define _odictnode_DEALLOC(node) \ do { \ Py_DECREF(_odictnode_KEY(node)); \ - PyMem_FREE((void *)node); \ + PyMem_Free((void *)node); \ } while (0) /* Repeated calls on the same node are no-ops. */ @@ -776,7 +776,7 @@ _odict_clear_nodes(PyODictObject *od) { _ODictNode *node, *next; - PyMem_FREE(od->od_fast_nodes); + PyMem_Free(od->od_fast_nodes); od->od_fast_nodes = NULL; od->od_fast_nodes_size = 0; od->od_resize_sentinel = NULL; @@ -1045,30 +1045,28 @@ OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, /* pop() */ -PyDoc_STRVAR(odict_pop__doc__, -"od.pop(k[,d]) -> v, remove specified key and return the corresponding\n\ - value. If key is not found, d is returned if given, otherwise KeyError\n\ - is raised.\n\ -\n\ - "); - /* forward */ static PyObject * _odict_popkey(PyObject *, PyObject *, PyObject *); /* Skips __missing__() calls. */ -static PyObject * -odict_pop(PyObject *od, PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = {"key", "default", 0}; - PyObject *key, *failobj = NULL; +/*[clinic input] +OrderedDict.pop - /* borrowed */ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:pop", kwlist, - &key, &failobj)) { - return NULL; - } + key: object + default: object = NULL + +od.pop(key[,default]) -> v, remove specified key and return the corresponding value. + +If the key is not found, return the default if given; otherwise, +raise a KeyError. +[clinic start generated code]*/ - return _odict_popkey(od, key, failobj); +static PyObject * +OrderedDict_pop_impl(PyODictObject *self, PyObject *key, + PyObject *default_value) +/*[clinic end generated code: output=7a6447d104e7494b input=7efe36601007dff7]*/ +{ + return _odict_popkey((PyObject *)self, key, default_value); } static PyObject * @@ -1363,8 +1361,7 @@ static PyMethodDef odict_methods[] = { {"__reduce__", (PyCFunction)odict_reduce, METH_NOARGS, odict_reduce__doc__}, ORDEREDDICT_SETDEFAULT_METHODDEF - {"pop", (PyCFunction)(void(*)(void))odict_pop, - METH_VARARGS | METH_KEYWORDS, odict_pop__doc__}, + ORDEREDDICT_POP_METHODDEF ORDEREDDICT_POPITEM_METHODDEF {"keys", odictkeys_new, METH_NOARGS, odict_keys__doc__}, diff --git a/contrib/tools/python3/src/Objects/rangeobject.c b/contrib/tools/python3/src/Objects/rangeobject.c index d7076ac824..a848d67a65 100644 --- a/contrib/tools/python3/src/Objects/rangeobject.c +++ b/contrib/tools/python3/src/Objects/rangeobject.c @@ -1,8 +1,9 @@ /* Range object implementation */ #include "Python.h" -#include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_tupleobject.h" +#include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_tuple.h" // _PyTuple_ITEMS() #include "structmember.h" // PyMemberDef /* Support objects whose length is > PY_SSIZE_T_MAX. @@ -105,10 +106,10 @@ range_from_array(PyTypeObject *type, PyObject *const *args, Py_ssize_t num_args) if (!stop) { return NULL; } - Py_INCREF(_PyLong_Zero); - start = _PyLong_Zero; - Py_INCREF(_PyLong_One); - step = _PyLong_One; + start = _PyLong_GetZero(); + Py_INCREF(start); + step = _PyLong_GetOne(); + Py_INCREF(step); break; case 0: PyErr_SetString(PyExc_TypeError, @@ -170,7 +171,7 @@ range_dealloc(rangeobject *r) Py_DECREF(r->stop); Py_DECREF(r->step); Py_DECREF(r->length); - PyObject_Del(r); + PyObject_Free(r); } /* Return number of items in range (lo, hi, step) as a PyLong object, @@ -190,7 +191,10 @@ compute_range_length(PyObject *start, PyObject *stop, PyObject *step) PyObject *tmp1 = NULL, *tmp2 = NULL, *result; /* holds sub-expression evaluations */ - cmp_result = PyObject_RichCompareBool(step, _PyLong_Zero, Py_GT); + PyObject *zero = _PyLong_GetZero(); // borrowed reference + PyObject *one = _PyLong_GetOne(); // borrowed reference + + cmp_result = PyObject_RichCompareBool(step, zero, Py_GT); if (cmp_result == -1) return NULL; @@ -212,19 +216,21 @@ compute_range_length(PyObject *start, PyObject *stop, PyObject *step) Py_DECREF(step); if (cmp_result < 0) return NULL; - return PyLong_FromLong(0); + result = zero; + Py_INCREF(result); + return result; } if ((tmp1 = PyNumber_Subtract(hi, lo)) == NULL) goto Fail; - if ((diff = PyNumber_Subtract(tmp1, _PyLong_One)) == NULL) + if ((diff = PyNumber_Subtract(tmp1, one)) == NULL) goto Fail; if ((tmp2 = PyNumber_FloorDivide(diff, step)) == NULL) goto Fail; - if ((result = PyNumber_Add(tmp2, _PyLong_One)) == NULL) + if ((result = PyNumber_Add(tmp2, one)) == NULL) goto Fail; Py_DECREF(tmp2); @@ -254,17 +260,24 @@ compute_item(rangeobject *r, PyObject *i) /* PyLong equivalent to: * return r->start + (i * r->step) */ - incr = PyNumber_Multiply(i, r->step); - if (!incr) - return NULL; - result = PyNumber_Add(r->start, incr); - Py_DECREF(incr); + if (r->step == _PyLong_GetOne()) { + result = PyNumber_Add(r->start, i); + } + else { + incr = PyNumber_Multiply(i, r->step); + if (!incr) { + return NULL; + } + result = PyNumber_Add(r->start, incr); + Py_DECREF(incr); + } return result; } static PyObject * compute_range_item(rangeobject *r, PyObject *arg) { + PyObject *zero = _PyLong_GetZero(); // borrowed reference int cmp_result; PyObject *i, *result; @@ -275,7 +288,7 @@ compute_range_item(rangeobject *r, PyObject *arg) * i = arg * } */ - cmp_result = PyObject_RichCompareBool(arg, _PyLong_Zero, Py_LT); + cmp_result = PyObject_RichCompareBool(arg, zero, Py_LT); if (cmp_result == -1) { return NULL; } @@ -294,7 +307,7 @@ compute_range_item(rangeobject *r, PyObject *arg) * <report index out of bounds> * } */ - cmp_result = PyObject_RichCompareBool(i, _PyLong_Zero, Py_LT); + cmp_result = PyObject_RichCompareBool(i, zero, Py_LT); if (cmp_result == 0) { cmp_result = PyObject_RichCompareBool(i, r->length, Py_GE); } @@ -369,6 +382,7 @@ fail: static int range_contains_long(rangeobject *r, PyObject *ob) { + PyObject *zero = _PyLong_GetZero(); // borrowed reference int cmp1, cmp2, cmp3; PyObject *tmp1 = NULL; PyObject *tmp2 = NULL; @@ -376,7 +390,7 @@ range_contains_long(rangeobject *r, PyObject *ob) /* Check if the value can possibly be in the range. */ - cmp1 = PyObject_RichCompareBool(r->step, _PyLong_Zero, Py_GT); + cmp1 = PyObject_RichCompareBool(r->step, zero, Py_GT); if (cmp1 == -1) goto end; if (cmp1 == 1) { /* positive steps: start <= ob < stop */ @@ -403,7 +417,7 @@ range_contains_long(rangeobject *r, PyObject *ob) if (tmp2 == NULL) goto end; /* result = ((int(ob) - start) % step) == 0 */ - result = PyObject_RichCompareBool(tmp2, _PyLong_Zero, Py_EQ); + result = PyObject_RichCompareBool(tmp2, zero, Py_EQ); end: Py_XDECREF(tmp1); Py_XDECREF(tmp2); @@ -454,7 +468,7 @@ range_equals(rangeobject *r0, rangeobject *r1) /* Return False or error to the caller. */ if (cmp_result != 1) return cmp_result; - cmp_result = PyObject_RichCompareBool(r0->length, _PyLong_One, Py_EQ); + cmp_result = PyObject_RichCompareBool(r0->length, _PyLong_GetOne(), Py_EQ); /* Return True or error to the caller. */ if (cmp_result != 0) return cmp_result; @@ -523,7 +537,7 @@ range_hash(rangeobject *r) else { Py_INCREF(r->start); PyTuple_SET_ITEM(t, 1, r->start); - cmp_result = PyObject_RichCompareBool(r->length, _PyLong_One, Py_EQ); + cmp_result = PyObject_RichCompareBool(r->length, _PyLong_GetOne(), Py_EQ); if (cmp_result == -1) goto end; if (cmp_result == 1) { @@ -576,13 +590,19 @@ range_index(rangeobject *r, PyObject *ob) return NULL; if (contains) { - PyObject *idx, *tmp = PyNumber_Subtract(ob, r->start); - if (tmp == NULL) + PyObject *idx = PyNumber_Subtract(ob, r->start); + if (idx == NULL) { return NULL; + } + + if (r->step == _PyLong_GetOne()) { + return idx; + } + /* idx = (ob - r.start) // r.step */ - idx = PyNumber_FloorDivide(tmp, r->step); - Py_DECREF(tmp); - return idx; + PyObject *sidx = PyNumber_FloorDivide(idx, r->step); + Py_DECREF(idx); + return sidx; } /* object is not in the range */ @@ -715,7 +735,7 @@ PyTypeObject PyRange_Type = { PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_SEQUENCE, /* tp_flags */ range_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -954,14 +974,15 @@ longrangeiter_reduce(longrangeiterobject *r, PyObject *Py_UNUSED(ignored)) static PyObject * longrangeiter_setstate(longrangeiterobject *r, PyObject *state) { + PyObject *zero = _PyLong_GetZero(); // borrowed reference int cmp; /* clip the value */ - cmp = PyObject_RichCompareBool(state, _PyLong_Zero, Py_LT); + cmp = PyObject_RichCompareBool(state, zero, Py_LT); if (cmp < 0) return NULL; if (cmp > 0) { - state = _PyLong_Zero; + state = zero; } else { cmp = PyObject_RichCompareBool(r->len, state, Py_LT); @@ -992,7 +1013,7 @@ longrangeiter_dealloc(longrangeiterobject *r) Py_XDECREF(r->start); Py_XDECREF(r->step); Py_XDECREF(r->len); - PyObject_Del(r); + PyObject_Free(r); } static PyObject * @@ -1002,7 +1023,7 @@ longrangeiter_next(longrangeiterobject *r) if (PyObject_RichCompareBool(r->index, r->len, Py_LT) != 1) return NULL; - new_index = PyNumber_Add(r->index, _PyLong_One); + new_index = PyNumber_Add(r->index, _PyLong_GetOne()); if (!new_index) return NULL; @@ -1109,7 +1130,7 @@ range_iter(PyObject *seq) it->start = r->start; it->step = r->step; it->len = r->length; - it->index = _PyLong_Zero; + it->index = _PyLong_GetZero(); Py_INCREF(it->start); Py_INCREF(it->step); Py_INCREF(it->len); @@ -1197,7 +1218,7 @@ long_range: it->len = range->length; Py_INCREF(it->len); - diff = PyNumber_Subtract(it->len, _PyLong_One); + diff = PyNumber_Subtract(it->len, _PyLong_GetOne()); if (!diff) goto create_failure; @@ -1216,7 +1237,7 @@ long_range: if (!it->step) goto create_failure; - it->index = _PyLong_Zero; + it->index = _PyLong_GetZero(); Py_INCREF(it->index); return (PyObject *)it; diff --git a/contrib/tools/python3/src/Objects/setobject.c b/contrib/tools/python3/src/Objects/setobject.c index 6d156bd4e0..e8ba32e578 100644 --- a/contrib/tools/python3/src/Objects/setobject.c +++ b/contrib/tools/python3/src/Objects/setobject.c @@ -16,7 +16,7 @@ reduces the cost of hash collisions because consecutive memory accesses tend to be much cheaper than scattered probes. After LINEAR_PROBES steps, we then use more of the upper bits from the hash value and apply a simple - linear congruential random number genearator. This helps break-up long + linear congruential random number generator. This helps break-up long chains of collisions. All arithmetic on hash should ignore overflow. @@ -103,6 +103,7 @@ static int set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) { setentry *table; + setentry *freeslot; setentry *entry; size_t perturb; size_t mask; @@ -118,6 +119,7 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) mask = so->mask; i = (size_t)hash & mask; + freeslot = NULL; perturb = hash; while (1) { @@ -125,7 +127,7 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) probes = (i + LINEAR_PROBES <= mask) ? LINEAR_PROBES: 0; do { if (entry->hash == 0 && entry->key == NULL) - goto found_unused; + goto found_unused_or_dummy; if (entry->hash == hash) { PyObject *startkey = entry->key; assert(startkey != dummy); @@ -147,12 +149,24 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) goto restart; mask = so->mask; } + else if (entry->hash == -1) { + assert (entry->key == dummy); + freeslot = entry; + } entry++; } while (probes--); perturb >>= PERTURB_SHIFT; i = (i * 5 + 1 + perturb) & mask; } + found_unused_or_dummy: + if (freeslot == NULL) + goto found_unused; + so->used++; + freeslot->key = key; + freeslot->hash = hash; + return 0; + found_unused: so->fill++; so->used++; @@ -289,7 +303,7 @@ set_table_resize(PySetObject *so, Py_ssize_t minused) } if (is_oldtable_malloced) - PyMem_DEL(oldtable); + PyMem_Free(oldtable); return 0; } @@ -424,7 +438,7 @@ set_clear_internal(PySetObject *so) } if (table_is_malloced) - PyMem_DEL(table); + PyMem_Free(table); return 0; } @@ -484,7 +498,7 @@ set_dealloc(PySetObject *so) } } if (so->table != so->smalltable) - PyMem_DEL(so->table); + PyMem_Free(so->table); Py_TYPE(so)->tp_free(so); Py_TRASHCAN_END } @@ -522,7 +536,7 @@ set_repr(PySetObject *so) goto done; listrepr = tmp; - if (!Py_IS_TYPE(so, &PySet_Type)) + if (!PySet_CheckExact(so)) result = PyUnicode_FromFormat("%s({%U})", Py_TYPE(so)->tp_name, listrepr); @@ -975,9 +989,6 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable) return make_new_set(type, iterable); } -/* The empty frozenset is a singleton */ -static PyObject *emptyfrozenset = NULL; - static PyObject * make_new_frozenset(PyTypeObject *type, PyObject *iterable) { @@ -985,26 +996,12 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable) return make_new_set(type, iterable); } - if (iterable != NULL) { - if (PyFrozenSet_CheckExact(iterable)) { - /* frozenset(f) is idempotent */ - Py_INCREF(iterable); - return iterable; - } - PyObject *res = make_new_set((PyTypeObject *)type, iterable); - if (res == NULL || PySet_GET_SIZE(res) != 0) { - return res; - } - /* If the created frozenset is empty, return the empty frozenset singleton instead */ - Py_DECREF(res); - } - - // The empty frozenset is a singleton - if (emptyfrozenset == NULL) { - emptyfrozenset = make_new_set((PyTypeObject *)type, NULL); + if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) { + /* frozenset(f) is idempotent */ + Py_INCREF(iterable); + return iterable; } - Py_XINCREF(emptyfrozenset); - return emptyfrozenset; + return make_new_set((PyTypeObject *)type, iterable); } static PyObject * @@ -1530,7 +1527,7 @@ set_difference(PySetObject *so, PyObject *other) key = entry->key; hash = entry->hash; Py_INCREF(key); - rv = _PyDict_Contains(other, key, hash); + rv = _PyDict_Contains_KnownHash(other, key, hash); if (rv < 0) { Py_DECREF(result); Py_DECREF(key); @@ -2141,7 +2138,8 @@ PyTypeObject PySet_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | + _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ set_doc, /* tp_doc */ (traverseproc)set_traverse, /* tp_traverse */ (inquiry)set_clear_internal, /* tp_clear */ @@ -2241,7 +2239,8 @@ PyTypeObject PyFrozenSet_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ + Py_TPFLAGS_BASETYPE | + _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ frozenset_doc, /* tp_doc */ (traverseproc)set_traverse, /* tp_traverse */ (inquiry)set_clear_internal, /* tp_clear */ @@ -2330,12 +2329,6 @@ PySet_Add(PyObject *anyset, PyObject *key) return set_add_key((PySetObject *)anyset, key); } -void -_PySet_Fini(void) -{ - Py_CLEAR(emptyfrozenset); -} - int _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash) { @@ -2558,4 +2551,3 @@ static PyObject _dummy_struct = { _PyObject_EXTRA_INIT 2, &_PySetDummy_Type }; - diff --git a/contrib/tools/python3/src/Objects/sliceobject.c b/contrib/tools/python3/src/Objects/sliceobject.c index 391711f711..22fb7c61c3 100644 --- a/contrib/tools/python3/src/Objects/sliceobject.c +++ b/contrib/tools/python3/src/Objects/sliceobject.c @@ -15,7 +15,8 @@ this type and there is exactly one in existence. #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_object.h" +#include "pycore_long.h" // _PyLong_GetZero() +#include "pycore_object.h" // _PyObject_GC_TRACK() #include "structmember.h" // PyMemberDef static PyObject * @@ -95,16 +96,12 @@ PyObject _Py_EllipsisObject = { /* Slice object implementation */ -/* Using a cache is very effective since typically only a single slice is - * created and then deleted again - */ -static PySliceObject *slice_cache = NULL; -void _PySlice_Fini(void) +void _PySlice_Fini(PyInterpreterState *interp) { - PySliceObject *obj = slice_cache; + PySliceObject *obj = interp->slice_cache; if (obj != NULL) { - slice_cache = NULL; + interp->slice_cache = NULL; PyObject_GC_Del(obj); } } @@ -116,26 +113,35 @@ void _PySlice_Fini(void) PyObject * PySlice_New(PyObject *start, PyObject *stop, PyObject *step) { + if (step == NULL) { + step = Py_None; + } + if (start == NULL) { + start = Py_None; + } + if (stop == NULL) { + stop = Py_None; + } + + PyInterpreterState *interp = _PyInterpreterState_GET(); PySliceObject *obj; - if (slice_cache != NULL) { - obj = slice_cache; - slice_cache = NULL; + if (interp->slice_cache != NULL) { + obj = interp->slice_cache; + interp->slice_cache = NULL; _Py_NewReference((PyObject *)obj); - } else { + } + else { obj = PyObject_GC_New(PySliceObject, &PySlice_Type); - if (obj == NULL) + if (obj == NULL) { return NULL; + } } - if (step == NULL) step = Py_None; Py_INCREF(step); - if (start == NULL) start = Py_None; - Py_INCREF(start); - if (stop == NULL) stop = Py_None; - Py_INCREF(stop); - obj->step = step; + Py_INCREF(start); obj->start = start; + Py_INCREF(stop); obj->stop = stop; _PyObject_GC_TRACK(obj); @@ -324,14 +330,17 @@ Create a slice object. This is used for extended slicing (e.g. a[0:10:2])."); static void slice_dealloc(PySliceObject *r) { + PyInterpreterState *interp = _PyInterpreterState_GET(); _PyObject_GC_UNTRACK(r); Py_DECREF(r->step); Py_DECREF(r->start); Py_DECREF(r->stop); - if (slice_cache == NULL) - slice_cache = r; - else + if (interp->slice_cache == NULL) { + interp->slice_cache = r; + } + else { PyObject_GC_Del(r); + } } static PyObject * @@ -379,7 +388,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, /* Convert step to an integer; raise for zero step. */ if (self->step == Py_None) { - step = _PyLong_One; + step = _PyLong_GetOne(); Py_INCREF(step); step_is_negative = 0; } @@ -408,7 +417,7 @@ _PySlice_GetLongIndices(PySliceObject *self, PyObject *length, goto error; } else { - lower = _PyLong_Zero; + lower = _PyLong_GetZero(); Py_INCREF(lower); upper = length; Py_INCREF(upper); diff --git a/contrib/tools/python3/src/Objects/stringlib/asciilib.h b/contrib/tools/python3/src/Objects/stringlib/asciilib.h index e69a2c076e..7749e8fb33 100644 --- a/contrib/tools/python3/src/Objects/stringlib/asciilib.h +++ b/contrib/tools/python3/src/Objects/stringlib/asciilib.h @@ -11,7 +11,6 @@ #define STRINGLIB_CHAR Py_UCS1 #define STRINGLIB_TYPE_NAME "unicode" #define STRINGLIB_PARSE_CODE "U" -#define STRINGLIB_EMPTY unicode_empty #define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE #define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK #define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL diff --git a/contrib/tools/python3/src/Objects/stringlib/clinic/transmogrify.h.h b/contrib/tools/python3/src/Objects/stringlib/clinic/transmogrify.h.h index 8a3a060f12..a5135a0cba 100644 --- a/contrib/tools/python3/src/Objects/stringlib/clinic/transmogrify.h.h +++ b/contrib/tools/python3/src/Objects/stringlib/clinic/transmogrify.h.h @@ -33,11 +33,6 @@ stringlib_expandtabs(PyObject *self, PyObject *const *args, Py_ssize_t nargs, Py if (!noptargs) { goto skip_optional_pos; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } tabsize = _PyLong_AsInt(args[0]); if (tabsize == -1 && PyErr_Occurred()) { goto exit; @@ -73,14 +68,9 @@ stringlib_ljust(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("ljust", nargs, 1, 2)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -134,14 +124,9 @@ stringlib_rjust(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("rjust", nargs, 1, 2)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -195,14 +180,9 @@ stringlib_center(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (!_PyArg_CheckPositional("center", nargs, 1, 2)) { goto exit; } - if (PyFloat_Check(args[0])) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(args[0]); + PyObject *iobj = _PyNumber_Index(args[0]); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -252,14 +232,9 @@ stringlib_zfill(PyObject *self, PyObject *arg) PyObject *return_value = NULL; Py_ssize_t width; - if (PyFloat_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "integer argument expected, got float" ); - goto exit; - } { Py_ssize_t ival = -1; - PyObject *iobj = PyNumber_Index(arg); + PyObject *iobj = _PyNumber_Index(arg); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); @@ -274,4 +249,4 @@ stringlib_zfill(PyObject *self, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=15be047aef999b4e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2d9abc7b1cffeca6 input=a9049054013a1b77]*/ diff --git a/contrib/tools/python3/src/Objects/stringlib/codecs.h b/contrib/tools/python3/src/Objects/stringlib/codecs.h index 9b2a29ba3b..b17cda18f5 100644 --- a/contrib/tools/python3/src/Objects/stringlib/codecs.h +++ b/contrib/tools/python3/src/Objects/stringlib/codecs.h @@ -4,16 +4,16 @@ # error "codecs.h is specific to Unicode" #endif -#include "pycore_byteswap.h" // _Py_bswap32() +#include "pycore_bitutils.h" // _Py_bswap32() -/* Mask to quickly check whether a C 'long' contains a +/* Mask to quickly check whether a C 'size_t' contains a non-ASCII, UTF8-encoded char. */ -#if (SIZEOF_LONG == 8) -# define ASCII_CHAR_MASK 0x8080808080808080UL -#elif (SIZEOF_LONG == 4) -# define ASCII_CHAR_MASK 0x80808080UL +#if (SIZEOF_SIZE_T == 8) +# define ASCII_CHAR_MASK 0x8080808080808080ULL +#elif (SIZEOF_SIZE_T == 4) +# define ASCII_CHAR_MASK 0x80808080U #else -# error C 'long' size should be either 4 or 8! +# error C 'size_t' size should be either 4 or 8! #endif /* 10xxxxxx */ @@ -26,7 +26,6 @@ STRINGLIB(utf8_decode)(const char **inptr, const char *end, { Py_UCS4 ch; const char *s = *inptr; - const char *aligned_end = (const char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG); STRINGLIB_CHAR *p = dest + *outpos; while (s < end) { @@ -36,19 +35,19 @@ STRINGLIB(utf8_decode)(const char **inptr, const char *end, /* Fast path for runs of ASCII characters. Given that common UTF-8 input will consist of an overwhelming majority of ASCII characters, we try to optimize for this case by checking - as many characters as a C 'long' can contain. + as many characters as a C 'size_t' can contain. First, check if we can do an aligned read, as most CPUs have a penalty for unaligned reads. */ - if (_Py_IS_ALIGNED(s, SIZEOF_LONG)) { + if (_Py_IS_ALIGNED(s, ALIGNOF_SIZE_T)) { /* Help register allocation */ const char *_s = s; STRINGLIB_CHAR *_p = p; - while (_s < aligned_end) { - /* Read a whole long at a time (either 4 or 8 bytes), + while (_s + SIZEOF_SIZE_T <= end) { + /* Read a whole size_t at a time (either 4 or 8 bytes), and do a fast unrolled copy if it only contains ASCII characters. */ - unsigned long value = *(const unsigned long *) _s; + size_t value = *(const size_t *) _s; if (value & ASCII_CHAR_MASK) break; #if PY_LITTLE_ENDIAN @@ -56,14 +55,14 @@ STRINGLIB(utf8_decode)(const char **inptr, const char *end, _p[1] = (STRINGLIB_CHAR)((value >> 8) & 0xFFu); _p[2] = (STRINGLIB_CHAR)((value >> 16) & 0xFFu); _p[3] = (STRINGLIB_CHAR)((value >> 24) & 0xFFu); -# if SIZEOF_LONG == 8 +# if SIZEOF_SIZE_T == 8 _p[4] = (STRINGLIB_CHAR)((value >> 32) & 0xFFu); _p[5] = (STRINGLIB_CHAR)((value >> 40) & 0xFFu); _p[6] = (STRINGLIB_CHAR)((value >> 48) & 0xFFu); _p[7] = (STRINGLIB_CHAR)((value >> 56) & 0xFFu); # endif #else -# if SIZEOF_LONG == 8 +# if SIZEOF_SIZE_T == 8 _p[0] = (STRINGLIB_CHAR)((value >> 56) & 0xFFu); _p[1] = (STRINGLIB_CHAR)((value >> 48) & 0xFFu); _p[2] = (STRINGLIB_CHAR)((value >> 40) & 0xFFu); @@ -79,8 +78,8 @@ STRINGLIB(utf8_decode)(const char **inptr, const char *end, _p[3] = (STRINGLIB_CHAR)(value & 0xFFu); # endif #endif - _s += SIZEOF_LONG; - _p += SIZEOF_LONG; + _s += SIZEOF_SIZE_T; + _p += SIZEOF_SIZE_T; } s = _s; p = _p; @@ -496,8 +495,6 @@ STRINGLIB(utf16_decode)(const unsigned char **inptr, const unsigned char *e, int native_ordering) { Py_UCS4 ch; - const unsigned char *aligned_end = - (const unsigned char *) _Py_ALIGN_DOWN(e, SIZEOF_LONG); const unsigned char *q = *inptr; STRINGLIB_CHAR *p = dest + *outpos; /* Offsets from q for retrieving byte pairs in the right order. */ @@ -512,10 +509,10 @@ STRINGLIB(utf16_decode)(const unsigned char **inptr, const unsigned char *e, Py_UCS4 ch2; /* First check for possible aligned read of a C 'long'. Unaligned reads are more expensive, better to defer to another iteration. */ - if (_Py_IS_ALIGNED(q, SIZEOF_LONG)) { + if (_Py_IS_ALIGNED(q, ALIGNOF_LONG)) { /* Fast path for runs of in-range non-surrogate chars. */ const unsigned char *_q = q; - while (_q < aligned_end) { + while (_q + SIZEOF_LONG <= e) { unsigned long block = * (const unsigned long *) _q; if (native_ordering) { /* Can use buffer directly */ diff --git a/contrib/tools/python3/src/Objects/stringlib/fastsearch.h b/contrib/tools/python3/src/Objects/stringlib/fastsearch.h index 56a4467d35..6574720b60 100644 --- a/contrib/tools/python3/src/Objects/stringlib/fastsearch.h +++ b/contrib/tools/python3/src/Objects/stringlib/fastsearch.h @@ -9,10 +9,16 @@ /* note: fastsearch may access s[n], which isn't a problem when using Python's ordinary string types, but may cause problems if you're using this code in other contexts. also, the count mode returns -1 - if there cannot possible be a match in the target string, and 0 if + if there cannot possibly be a match in the target string, and 0 if it has actually checked for matches, but didn't find any. callers beware! */ +/* If the strings are long enough, use Crochemore and Perrin's Two-Way + algorithm, which has worst-case O(n) runtime and best-case O(n/k). + Also compute a table of shifts to achieve O(n/k) in more cases, + and often (data dependent) deduce larger shifts than pure C&P can + deduce. */ + #define FAST_COUNT 0 #define FAST_SEARCH 1 #define FAST_RSEARCH 2 @@ -160,6 +166,353 @@ STRINGLIB(rfind_char)(const STRINGLIB_CHAR* s, Py_ssize_t n, STRINGLIB_CHAR ch) #undef MEMCHR_CUT_OFF +/* Change to a 1 to see logging comments walk through the algorithm. */ +#if 0 && STRINGLIB_SIZEOF_CHAR == 1 +# define LOG(...) printf(__VA_ARGS__) +# define LOG_STRING(s, n) printf("\"%.*s\"", n, s) +#else +# define LOG(...) +# define LOG_STRING(s, n) +#endif + +Py_LOCAL_INLINE(Py_ssize_t) +STRINGLIB(_lex_search)(const STRINGLIB_CHAR *needle, Py_ssize_t len_needle, + Py_ssize_t *return_period, int invert_alphabet) +{ + /* Do a lexicographic search. Essentially this: + >>> max(needle[i:] for i in range(len(needle)+1)) + Also find the period of the right half. */ + Py_ssize_t max_suffix = 0; + Py_ssize_t candidate = 1; + Py_ssize_t k = 0; + // The period of the right half. + Py_ssize_t period = 1; + + while (candidate + k < len_needle) { + // each loop increases candidate + k + max_suffix + STRINGLIB_CHAR a = needle[candidate + k]; + STRINGLIB_CHAR b = needle[max_suffix + k]; + // check if the suffix at candidate is better than max_suffix + if (invert_alphabet ? (b < a) : (a < b)) { + // Fell short of max_suffix. + // The next k + 1 characters are non-increasing + // from candidate, so they won't start a maximal suffix. + candidate += k + 1; + k = 0; + // We've ruled out any period smaller than what's + // been scanned since max_suffix. + period = candidate - max_suffix; + } + else if (a == b) { + if (k + 1 != period) { + // Keep scanning the equal strings + k++; + } + else { + // Matched a whole period. + // Start matching the next period. + candidate += period; + k = 0; + } + } + else { + // Did better than max_suffix, so replace it. + max_suffix = candidate; + candidate++; + k = 0; + period = 1; + } + } + *return_period = period; + return max_suffix; +} + +Py_LOCAL_INLINE(Py_ssize_t) +STRINGLIB(_factorize)(const STRINGLIB_CHAR *needle, + Py_ssize_t len_needle, + Py_ssize_t *return_period) +{ + /* Do a "critical factorization", making it so that: + >>> needle = (left := needle[:cut]) + (right := needle[cut:]) + where the "local period" of the cut is maximal. + + The local period of the cut is the minimal length of a string w + such that (left endswith w or w endswith left) + and (right startswith w or w startswith left). + + The Critical Factorization Theorem says that this maximal local + period is the global period of the string. + + Crochemore and Perrin (1991) show that this cut can be computed + as the later of two cuts: one that gives a lexicographically + maximal right half, and one that gives the same with the + with respect to a reversed alphabet-ordering. + + This is what we want to happen: + >>> x = "GCAGAGAG" + >>> cut, period = factorize(x) + >>> x[:cut], (right := x[cut:]) + ('GC', 'AGAGAG') + >>> period # right half period + 2 + >>> right[period:] == right[:-period] + True + + This is how the local period lines up in the above example: + GC | AGAGAG + AGAGAGC = AGAGAGC + The length of this minimal repetition is 7, which is indeed the + period of the original string. */ + + Py_ssize_t cut1, period1, cut2, period2, cut, period; + cut1 = STRINGLIB(_lex_search)(needle, len_needle, &period1, 0); + cut2 = STRINGLIB(_lex_search)(needle, len_needle, &period2, 1); + + // Take the later cut. + if (cut1 > cut2) { + period = period1; + cut = cut1; + } + else { + period = period2; + cut = cut2; + } + + LOG("split: "); LOG_STRING(needle, cut); + LOG(" + "); LOG_STRING(needle + cut, len_needle - cut); + LOG("\n"); + + *return_period = period; + return cut; +} + +#define SHIFT_TYPE uint8_t +#define NOT_FOUND ((1U<<(8*sizeof(SHIFT_TYPE))) - 1U) +#define SHIFT_OVERFLOW (NOT_FOUND - 1U) + +#define TABLE_SIZE_BITS 6 +#define TABLE_SIZE (1U << TABLE_SIZE_BITS) +#define TABLE_MASK (TABLE_SIZE - 1U) + +typedef struct STRINGLIB(_pre) { + const STRINGLIB_CHAR *needle; + Py_ssize_t len_needle; + Py_ssize_t cut; + Py_ssize_t period; + int is_periodic; + SHIFT_TYPE table[TABLE_SIZE]; +} STRINGLIB(prework); + + +Py_LOCAL_INLINE(void) +STRINGLIB(_preprocess)(const STRINGLIB_CHAR *needle, Py_ssize_t len_needle, + STRINGLIB(prework) *p) +{ + p->needle = needle; + p->len_needle = len_needle; + p->cut = STRINGLIB(_factorize)(needle, len_needle, &(p->period)); + assert(p->period + p->cut <= len_needle); + p->is_periodic = (0 == memcmp(needle, + needle + p->period, + p->cut * STRINGLIB_SIZEOF_CHAR)); + if (p->is_periodic) { + assert(p->cut <= len_needle/2); + assert(p->cut < p->period); + } + else { + // A lower bound on the period + p->period = Py_MAX(p->cut, len_needle - p->cut) + 1; + } + // Now fill up a table + memset(&(p->table[0]), 0xff, TABLE_SIZE*sizeof(SHIFT_TYPE)); + assert(p->table[0] == NOT_FOUND); + assert(p->table[TABLE_MASK] == NOT_FOUND); + for (Py_ssize_t i = 0; i < len_needle; i++) { + Py_ssize_t shift = len_needle - i; + if (shift > SHIFT_OVERFLOW) { + shift = SHIFT_OVERFLOW; + } + p->table[needle[i] & TABLE_MASK] = Py_SAFE_DOWNCAST(shift, + Py_ssize_t, + SHIFT_TYPE); + } +} + +Py_LOCAL_INLINE(Py_ssize_t) +STRINGLIB(_two_way)(const STRINGLIB_CHAR *haystack, Py_ssize_t len_haystack, + STRINGLIB(prework) *p) +{ + // Crochemore and Perrin's (1991) Two-Way algorithm. + // See http://www-igm.univ-mlv.fr/~lecroq/string/node26.html#SECTION00260 + Py_ssize_t len_needle = p->len_needle; + Py_ssize_t cut = p->cut; + Py_ssize_t period = p->period; + const STRINGLIB_CHAR *needle = p->needle; + const STRINGLIB_CHAR *window = haystack; + const STRINGLIB_CHAR *last_window = haystack + len_haystack - len_needle; + SHIFT_TYPE *table = p->table; + LOG("===== Two-way: \"%s\" in \"%s\". =====\n", needle, haystack); + + if (p->is_periodic) { + LOG("Needle is periodic.\n"); + Py_ssize_t memory = 0; + periodicwindowloop: + while (window <= last_window) { + Py_ssize_t i = Py_MAX(cut, memory); + + // Visualize the line-up: + LOG("> "); LOG_STRING(haystack, len_haystack); + LOG("\n> "); LOG("%*s", window - haystack, ""); + LOG_STRING(needle, len_needle); + LOG("\n> "); LOG("%*s", window - haystack + i, ""); + LOG(" ^ <-- cut\n"); + + if (window[i] != needle[i]) { + // Sunday's trick: if we're going to jump, we might + // as well jump to line up the character *after* the + // current window. + STRINGLIB_CHAR first_outside = window[len_needle]; + SHIFT_TYPE shift = table[first_outside & TABLE_MASK]; + if (shift == NOT_FOUND) { + LOG("\"%c\" not found. Skipping entirely.\n", + first_outside); + window += len_needle + 1; + } + else { + LOG("Shifting to line up \"%c\".\n", first_outside); + Py_ssize_t memory_shift = i - cut + 1; + window += Py_MAX(shift, memory_shift); + } + memory = 0; + goto periodicwindowloop; + } + for (i = i + 1; i < len_needle; i++) { + if (needle[i] != window[i]) { + LOG("Right half does not match. Jump ahead by %d.\n", + i - cut + 1); + window += i - cut + 1; + memory = 0; + goto periodicwindowloop; + } + } + for (i = memory; i < cut; i++) { + if (needle[i] != window[i]) { + LOG("Left half does not match. Jump ahead by period %d.\n", + period); + window += period; + memory = len_needle - period; + goto periodicwindowloop; + } + } + LOG("Left half matches. Returning %d.\n", + window - haystack); + return window - haystack; + } + } + else { + LOG("Needle is not periodic.\n"); + assert(cut < len_needle); + STRINGLIB_CHAR needle_cut = needle[cut]; + windowloop: + while (window <= last_window) { + + // Visualize the line-up: + LOG("> "); LOG_STRING(haystack, len_haystack); + LOG("\n> "); LOG("%*s", window - haystack, ""); + LOG_STRING(needle, len_needle); + LOG("\n> "); LOG("%*s", window - haystack + cut, ""); + LOG(" ^ <-- cut\n"); + + if (window[cut] != needle_cut) { + // Sunday's trick: if we're going to jump, we might + // as well jump to line up the character *after* the + // current window. + STRINGLIB_CHAR first_outside = window[len_needle]; + SHIFT_TYPE shift = table[first_outside & TABLE_MASK]; + if (shift == NOT_FOUND) { + LOG("\"%c\" not found. Skipping entirely.\n", + first_outside); + window += len_needle + 1; + } + else { + LOG("Shifting to line up \"%c\".\n", first_outside); + window += shift; + } + goto windowloop; + } + for (Py_ssize_t i = cut + 1; i < len_needle; i++) { + if (needle[i] != window[i]) { + LOG("Right half does not match. Advance by %d.\n", + i - cut + 1); + window += i - cut + 1; + goto windowloop; + } + } + for (Py_ssize_t i = 0; i < cut; i++) { + if (needle[i] != window[i]) { + LOG("Left half does not match. Advance by period %d.\n", + period); + window += period; + goto windowloop; + } + } + LOG("Left half matches. Returning %d.\n", window - haystack); + return window - haystack; + } + } + LOG("Not found. Returning -1.\n"); + return -1; +} + +Py_LOCAL_INLINE(Py_ssize_t) +STRINGLIB(_two_way_find)(const STRINGLIB_CHAR *haystack, + Py_ssize_t len_haystack, + const STRINGLIB_CHAR *needle, + Py_ssize_t len_needle) +{ + LOG("###### Finding \"%s\" in \"%s\".\n", needle, haystack); + STRINGLIB(prework) p; + STRINGLIB(_preprocess)(needle, len_needle, &p); + return STRINGLIB(_two_way)(haystack, len_haystack, &p); +} + +Py_LOCAL_INLINE(Py_ssize_t) +STRINGLIB(_two_way_count)(const STRINGLIB_CHAR *haystack, + Py_ssize_t len_haystack, + const STRINGLIB_CHAR *needle, + Py_ssize_t len_needle, + Py_ssize_t maxcount) +{ + LOG("###### Counting \"%s\" in \"%s\".\n", needle, haystack); + STRINGLIB(prework) p; + STRINGLIB(_preprocess)(needle, len_needle, &p); + Py_ssize_t index = 0, count = 0; + while (1) { + Py_ssize_t result; + result = STRINGLIB(_two_way)(haystack + index, + len_haystack - index, &p); + if (result == -1) { + return count; + } + count++; + if (count == maxcount) { + return maxcount; + } + index += result + len_needle; + } + return count; +} + +#undef SHIFT_TYPE +#undef NOT_FOUND +#undef SHIFT_OVERFLOW +#undef TABLE_SIZE_BITS +#undef TABLE_SIZE +#undef TABLE_MASK + +#undef LOG +#undef LOG_STRING + Py_LOCAL_INLINE(Py_ssize_t) FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n, const STRINGLIB_CHAR* p, Py_ssize_t m, @@ -195,10 +548,22 @@ FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n, } mlast = m - 1; - skip = mlast - 1; + skip = mlast; mask = 0; if (mode != FAST_RSEARCH) { + if (m >= 100 && w >= 2000 && w / m >= 5) { + /* For larger problems where the needle isn't a huge + percentage of the size of the haystack, the relatively + expensive O(m) startup cost of the two-way algorithm + will surely pay off. */ + if (mode == FAST_SEARCH) { + return STRINGLIB(_two_way_find)(s, n, p, m); + } + else { + return STRINGLIB(_two_way_count)(s, n, p, m, maxcount); + } + } const STRINGLIB_CHAR *ss = s + m - 1; const STRINGLIB_CHAR *pp = p + m - 1; @@ -207,41 +572,118 @@ FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n, /* process pattern[:-1] */ for (i = 0; i < mlast; i++) { STRINGLIB_BLOOM_ADD(mask, p[i]); - if (p[i] == p[mlast]) + if (p[i] == p[mlast]) { skip = mlast - i - 1; + } } /* process pattern[-1] outside the loop */ STRINGLIB_BLOOM_ADD(mask, p[mlast]); + if (m >= 100 && w >= 8000) { + /* To ensure that we have good worst-case behavior, + here's an adaptive version of the algorithm, where if + we match O(m) characters without any matches of the + entire needle, then we predict that the startup cost of + the two-way algorithm will probably be worth it. */ + Py_ssize_t hits = 0; + for (i = 0; i <= w; i++) { + if (ss[i] == pp[0]) { + /* candidate match */ + for (j = 0; j < mlast; j++) { + if (s[i+j] != p[j]) { + break; + } + } + if (j == mlast) { + /* got a match! */ + if (mode != FAST_COUNT) { + return i; + } + count++; + if (count == maxcount) { + return maxcount; + } + i = i + mlast; + continue; + } + /* miss: check if next character is part of pattern */ + if (!STRINGLIB_BLOOM(mask, ss[i+1])) { + i = i + m; + } + else { + i = i + skip; + } + hits += j + 1; + if (hits >= m / 4 && i < w - 1000) { + /* We've done O(m) fruitless comparisons + anyway, so spend the O(m) cost on the + setup for the two-way algorithm. */ + Py_ssize_t res; + if (mode == FAST_COUNT) { + res = STRINGLIB(_two_way_count)( + s+i, n-i, p, m, maxcount-count); + return count + res; + } + else { + res = STRINGLIB(_two_way_find)(s+i, n-i, p, m); + if (res == -1) { + return -1; + } + return i + res; + } + } + } + else { + /* skip: check if next character is part of pattern */ + if (!STRINGLIB_BLOOM(mask, ss[i+1])) { + i = i + m; + } + } + } + if (mode != FAST_COUNT) { + return -1; + } + return count; + } + /* The standard, non-adaptive version of the algorithm. */ for (i = 0; i <= w; i++) { /* note: using mlast in the skip path slows things down on x86 */ if (ss[i] == pp[0]) { /* candidate match */ - for (j = 0; j < mlast; j++) - if (s[i+j] != p[j]) + for (j = 0; j < mlast; j++) { + if (s[i+j] != p[j]) { break; + } + } if (j == mlast) { /* got a match! */ - if (mode != FAST_COUNT) + if (mode != FAST_COUNT) { return i; + } count++; - if (count == maxcount) + if (count == maxcount) { return maxcount; + } i = i + mlast; continue; } /* miss: check if next character is part of pattern */ - if (!STRINGLIB_BLOOM(mask, ss[i+1])) + if (!STRINGLIB_BLOOM(mask, ss[i+1])) { i = i + m; - else + } + else { i = i + skip; - } else { + } + } + else { /* skip: check if next character is part of pattern */ - if (!STRINGLIB_BLOOM(mask, ss[i+1])) + if (!STRINGLIB_BLOOM(mask, ss[i+1])) { i = i + m; + } } } - } else { /* FAST_RSEARCH */ + } + else { /* FAST_RSEARCH */ /* create compressed boyer-moore delta 1 table */ @@ -250,28 +692,36 @@ FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n, /* process pattern[:0:-1] */ for (i = mlast; i > 0; i--) { STRINGLIB_BLOOM_ADD(mask, p[i]); - if (p[i] == p[0]) + if (p[i] == p[0]) { skip = i - 1; + } } for (i = w; i >= 0; i--) { if (s[i] == p[0]) { /* candidate match */ - for (j = mlast; j > 0; j--) - if (s[i+j] != p[j]) + for (j = mlast; j > 0; j--) { + if (s[i+j] != p[j]) { break; - if (j == 0) + } + } + if (j == 0) { /* got a match! */ return i; + } /* miss: check if previous character is part of pattern */ - if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) + if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) { i = i - m; - else + } + else { i = i - skip; - } else { + } + } + else { /* skip: check if previous character is part of pattern */ - if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) + if (i > 0 && !STRINGLIB_BLOOM(mask, s[i-1])) { i = i - m; + } } } } diff --git a/contrib/tools/python3/src/Objects/stringlib/find_max_char.h b/contrib/tools/python3/src/Objects/stringlib/find_max_char.h index f4e0a7761d..b9ffdfc2e3 100644 --- a/contrib/tools/python3/src/Objects/stringlib/find_max_char.h +++ b/contrib/tools/python3/src/Objects/stringlib/find_max_char.h @@ -4,14 +4,14 @@ # error "find_max_char.h is specific to Unicode" #endif -/* Mask to quickly check whether a C 'long' contains a +/* Mask to quickly check whether a C 'size_t' contains a non-ASCII, UTF8-encoded char. */ -#if (SIZEOF_LONG == 8) -# define UCS1_ASCII_CHAR_MASK 0x8080808080808080UL -#elif (SIZEOF_LONG == 4) -# define UCS1_ASCII_CHAR_MASK 0x80808080UL +#if (SIZEOF_SIZE_T == 8) +# define UCS1_ASCII_CHAR_MASK 0x8080808080808080ULL +#elif (SIZEOF_SIZE_T == 4) +# define UCS1_ASCII_CHAR_MASK 0x80808080U #else -# error C 'long' size should be either 4 or 8! +# error C 'size_t' size should be either 4 or 8! #endif #if STRINGLIB_SIZEOF_CHAR == 1 @@ -20,18 +20,16 @@ Py_LOCAL_INLINE(Py_UCS4) STRINGLIB(find_max_char)(const STRINGLIB_CHAR *begin, const STRINGLIB_CHAR *end) { const unsigned char *p = (const unsigned char *) begin; - const unsigned char *aligned_end = - (const unsigned char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG); while (p < end) { - if (_Py_IS_ALIGNED(p, SIZEOF_LONG)) { + if (_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) { /* Help register allocation */ const unsigned char *_p = p; - while (_p < aligned_end) { - unsigned long value = *(const unsigned long *) _p; + while (_p + SIZEOF_SIZE_T <= end) { + size_t value = *(const size_t *) _p; if (value & UCS1_ASCII_CHAR_MASK) return 255; - _p += SIZEOF_LONG; + _p += SIZEOF_SIZE_T; } p = _p; if (p == end) diff --git a/contrib/tools/python3/src/Objects/stringlib/join.h b/contrib/tools/python3/src/Objects/stringlib/join.h index 53bcbdea7a..62e4c98de7 100644 --- a/contrib/tools/python3/src/Objects/stringlib/join.h +++ b/contrib/tools/python3/src/Objects/stringlib/join.h @@ -155,7 +155,7 @@ done: for (i = 0; i < nbufs; i++) PyBuffer_Release(&buffers[i]); if (buffers != static_buffers) - PyMem_FREE(buffers); + PyMem_Free(buffers); return res; } diff --git a/contrib/tools/python3/src/Objects/stringlib/partition.h b/contrib/tools/python3/src/Objects/stringlib/partition.h index ed32a6f2b3..bcc217697b 100644 --- a/contrib/tools/python3/src/Objects/stringlib/partition.h +++ b/contrib/tools/python3/src/Objects/stringlib/partition.h @@ -1,9 +1,14 @@ /* stringlib: partition implementation */ #ifndef STRINGLIB_FASTSEARCH_H -#error must include "stringlib/fastsearch.h" before including this module +# error must include "stringlib/fastsearch.h" before including this module #endif +#if !STRINGLIB_MUTABLE && !defined(STRINGLIB_GET_EMPTY) +# error "STRINGLIB_GET_EMPTY must be defined if STRINGLIB_MUTABLE is zero" +#endif + + Py_LOCAL_INLINE(PyObject*) STRINGLIB(partition)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, @@ -37,10 +42,12 @@ STRINGLIB(partition)(PyObject* str_obj, #else Py_INCREF(str_obj); PyTuple_SET_ITEM(out, 0, (PyObject*) str_obj); - Py_INCREF(STRINGLIB_EMPTY); - PyTuple_SET_ITEM(out, 1, (PyObject*) STRINGLIB_EMPTY); - Py_INCREF(STRINGLIB_EMPTY); - PyTuple_SET_ITEM(out, 2, (PyObject*) STRINGLIB_EMPTY); + PyObject *empty = (PyObject*)STRINGLIB_GET_EMPTY(); + assert(empty != NULL); + Py_INCREF(empty); + PyTuple_SET_ITEM(out, 1, empty); + Py_INCREF(empty); + PyTuple_SET_ITEM(out, 2, empty); #endif return out; } @@ -90,10 +97,12 @@ STRINGLIB(rpartition)(PyObject* str_obj, return NULL; } #else - Py_INCREF(STRINGLIB_EMPTY); - PyTuple_SET_ITEM(out, 0, (PyObject*) STRINGLIB_EMPTY); - Py_INCREF(STRINGLIB_EMPTY); - PyTuple_SET_ITEM(out, 1, (PyObject*) STRINGLIB_EMPTY); + PyObject *empty = (PyObject*)STRINGLIB_GET_EMPTY(); + assert(empty != NULL); + Py_INCREF(empty); + PyTuple_SET_ITEM(out, 0, empty); + Py_INCREF(empty); + PyTuple_SET_ITEM(out, 1, empty); Py_INCREF(str_obj); PyTuple_SET_ITEM(out, 2, (PyObject*) str_obj); #endif diff --git a/contrib/tools/python3/src/Objects/stringlib/stringdefs.h b/contrib/tools/python3/src/Objects/stringlib/stringdefs.h index ce27f3e408..88641b25d4 100644 --- a/contrib/tools/python3/src/Objects/stringlib/stringdefs.h +++ b/contrib/tools/python3/src/Objects/stringlib/stringdefs.h @@ -13,7 +13,6 @@ #define STRINGLIB_CHAR char #define STRINGLIB_TYPE_NAME "string" #define STRINGLIB_PARSE_CODE "S" -#define STRINGLIB_EMPTY nullstring #define STRINGLIB_ISSPACE Py_ISSPACE #define STRINGLIB_ISLINEBREAK(x) ((x == '\n') || (x == '\r')) #define STRINGLIB_ISDECIMAL(x) ((x >= '0') && (x <= '9')) diff --git a/contrib/tools/python3/src/Objects/stringlib/ucs1lib.h b/contrib/tools/python3/src/Objects/stringlib/ucs1lib.h index bc4b104f11..5b0b8a025e 100644 --- a/contrib/tools/python3/src/Objects/stringlib/ucs1lib.h +++ b/contrib/tools/python3/src/Objects/stringlib/ucs1lib.h @@ -11,7 +11,6 @@ #define STRINGLIB_CHAR Py_UCS1 #define STRINGLIB_TYPE_NAME "unicode" #define STRINGLIB_PARSE_CODE "U" -#define STRINGLIB_EMPTY unicode_empty #define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE #define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK #define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL diff --git a/contrib/tools/python3/src/Objects/stringlib/ucs2lib.h b/contrib/tools/python3/src/Objects/stringlib/ucs2lib.h index 86a1dff1b5..6af01511c5 100644 --- a/contrib/tools/python3/src/Objects/stringlib/ucs2lib.h +++ b/contrib/tools/python3/src/Objects/stringlib/ucs2lib.h @@ -11,7 +11,6 @@ #define STRINGLIB_CHAR Py_UCS2 #define STRINGLIB_TYPE_NAME "unicode" #define STRINGLIB_PARSE_CODE "U" -#define STRINGLIB_EMPTY unicode_empty #define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE #define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK #define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL diff --git a/contrib/tools/python3/src/Objects/stringlib/ucs4lib.h b/contrib/tools/python3/src/Objects/stringlib/ucs4lib.h index 3c32a93c96..39071a0cdf 100644 --- a/contrib/tools/python3/src/Objects/stringlib/ucs4lib.h +++ b/contrib/tools/python3/src/Objects/stringlib/ucs4lib.h @@ -11,7 +11,6 @@ #define STRINGLIB_CHAR Py_UCS4 #define STRINGLIB_TYPE_NAME "unicode" #define STRINGLIB_PARSE_CODE "U" -#define STRINGLIB_EMPTY unicode_empty #define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE #define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK #define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL diff --git a/contrib/tools/python3/src/Objects/stringlib/unicode_format.h b/contrib/tools/python3/src/Objects/stringlib/unicode_format.h index b526ad21b8..7152ec6ebe 100644 --- a/contrib/tools/python3/src/Objects/stringlib/unicode_format.h +++ b/contrib/tools/python3/src/Objects/stringlib/unicode_format.h @@ -983,7 +983,7 @@ static void formatteriter_dealloc(formatteriterobject *it) { Py_XDECREF(it->str); - PyObject_FREE(it); + PyObject_Free(it); } /* returns a tuple: @@ -1147,7 +1147,7 @@ static void fieldnameiter_dealloc(fieldnameiterobject *it) { Py_XDECREF(it->str); - PyObject_FREE(it); + PyObject_Free(it); } /* returns a tuple: diff --git a/contrib/tools/python3/src/Objects/stringlib/unicodedefs.h b/contrib/tools/python3/src/Objects/stringlib/unicodedefs.h index 3db5629e11..5ea79cd4f5 100644 --- a/contrib/tools/python3/src/Objects/stringlib/unicodedefs.h +++ b/contrib/tools/python3/src/Objects/stringlib/unicodedefs.h @@ -13,7 +13,6 @@ #define STRINGLIB_CHAR Py_UNICODE #define STRINGLIB_TYPE_NAME "unicode" #define STRINGLIB_PARSE_CODE "U" -#define STRINGLIB_EMPTY unicode_empty #define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE #define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK #define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL diff --git a/contrib/tools/python3/src/Objects/structseq.c b/contrib/tools/python3/src/Objects/structseq.c index 5a493c91e8..73795b677b 100644 --- a/contrib/tools/python3/src/Objects/structseq.c +++ b/contrib/tools/python3/src/Objects/structseq.c @@ -8,31 +8,46 @@ */ #include "Python.h" -#include "pycore_tupleobject.h" -#include "pycore_object.h" +#include "pycore_tuple.h" // _PyTuple_FromArray() +#include "pycore_object.h" // _PyObject_GC_TRACK() #include "structmember.h" // PyMemberDef +#include "pycore_structseq.h" // PyStructSequence_InitType() static const char visible_length_key[] = "n_sequence_fields"; static const char real_length_key[] = "n_fields"; static const char unnamed_fields_key[] = "n_unnamed_fields"; +static const char match_args_key[] = "__match_args__"; /* Fields with this name have only a field index, not a field name. They are only allowed for indices < n_visible_fields. */ const char * const PyStructSequence_UnnamedField = "unnamed field"; + _Py_IDENTIFIER(n_sequence_fields); _Py_IDENTIFIER(n_fields); _Py_IDENTIFIER(n_unnamed_fields); -#define VISIBLE_SIZE(op) Py_SIZE(op) -#define VISIBLE_SIZE_TP(tp) PyLong_AsSsize_t( \ - _PyDict_GetItemId((tp)->tp_dict, &PyId_n_sequence_fields)) +static Py_ssize_t +get_type_attr_as_size(PyTypeObject *tp, _Py_Identifier *id) +{ + PyObject *name = _PyUnicode_FromId(id); + if (name == NULL) { + return -1; + } + PyObject *v = PyDict_GetItemWithError(tp->tp_dict, name); + if (v == NULL && !PyErr_Occurred()) { + PyErr_Format(PyExc_TypeError, + "Missed attribute '%U' of type %s", + name, tp->tp_name); + } + return PyLong_AsSsize_t(v); +} -#define REAL_SIZE_TP(tp) PyLong_AsSsize_t( \ - _PyDict_GetItemId((tp)->tp_dict, &PyId_n_fields)) +#define VISIBLE_SIZE(op) Py_SIZE(op) +#define VISIBLE_SIZE_TP(tp) get_type_attr_as_size(tp, &PyId_n_sequence_fields) +#define REAL_SIZE_TP(tp) get_type_attr_as_size(tp, &PyId_n_fields) #define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op)) -#define UNNAMED_FIELDS_TP(tp) PyLong_AsSsize_t( \ - _PyDict_GetItemId((tp)->tp_dict, &PyId_n_unnamed_fields)) +#define UNNAMED_FIELDS_TP(tp) get_type_attr_as_size(tp, &PyId_n_unnamed_fields) #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op)) @@ -41,13 +56,20 @@ PyStructSequence_New(PyTypeObject *type) { PyStructSequence *obj; Py_ssize_t size = REAL_SIZE_TP(type), i; + if (size < 0) { + return NULL; + } + Py_ssize_t vsize = VISIBLE_SIZE_TP(type); + if (vsize < 0) { + return NULL; + } obj = PyObject_GC_NewVar(PyStructSequence, type, size); if (obj == NULL) return NULL; /* Hack the size of the variable object, so invisible fields don't appear to Python code. */ - Py_SET_SIZE(obj, VISIBLE_SIZE_TP(type)); + Py_SET_SIZE(obj, vsize); for (i = 0; i < size; i++) obj->ob_item[i] = NULL; @@ -94,7 +116,7 @@ structseq_dealloc(PyStructSequence *obj) Py_XDECREF(obj->ob_item[i]); } PyObject_GC_Del(obj); - if (PyType_GetFlags(tp) & Py_TPFLAGS_HEAPTYPE) { + if (_PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE)) { Py_DECREF(tp); } } @@ -121,6 +143,19 @@ structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict) PyStructSequence *res = NULL; Py_ssize_t len, min_len, max_len, i, n_unnamed_fields; + min_len = VISIBLE_SIZE_TP(type); + if (min_len < 0) { + return NULL; + } + max_len = REAL_SIZE_TP(type); + if (max_len < 0) { + return NULL; + } + n_unnamed_fields = UNNAMED_FIELDS_TP(type); + if (n_unnamed_fields < 0) { + return NULL; + } + arg = PySequence_Fast(arg, "constructor requires a sequence"); if (!arg) { @@ -136,10 +171,6 @@ structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict) } len = PySequence_Fast_GET_SIZE(arg); - min_len = VISIBLE_SIZE_TP(type); - max_len = REAL_SIZE_TP(type); - n_unnamed_fields = UNNAMED_FIELDS_TP(type); - if (min_len != max_len) { if (len < min_len) { PyErr_Format(PyExc_TypeError, @@ -177,18 +208,26 @@ structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict) Py_INCREF(v); res->ob_item[i] = v; } + Py_DECREF(arg); for (; i < max_len; ++i) { - if (dict && (ob = PyDict_GetItemString( - dict, type->tp_members[i-n_unnamed_fields].name))) { + if (dict == NULL) { + ob = Py_None; } else { - ob = Py_None; + ob = _PyDict_GetItemStringWithError(dict, + type->tp_members[i-n_unnamed_fields].name); + if (ob == NULL) { + if (PyErr_Occurred()) { + Py_DECREF(res); + return NULL; + } + ob = Py_None; + } } Py_INCREF(ob); res->ob_item[i] = ob; } - Py_DECREF(arg); _PyObject_GC_TRACK(res); return (PyObject*) res; } @@ -288,8 +327,14 @@ structseq_reduce(PyStructSequence* self, PyObject *Py_UNUSED(ignored)) Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields, i; n_fields = REAL_SIZE(self); + if (n_fields < 0) { + return NULL; + } n_visible_fields = VISIBLE_SIZE(self); n_unnamed_fields = UNNAMED_FIELDS(self); + if (n_unnamed_fields < 0) { + return NULL; + } tup = _PyTuple_FromArray(self->ob_item, n_visible_fields); if (!tup) goto error; @@ -356,7 +401,40 @@ initialize_structseq_dict(PyStructSequence_Desc *desc, PyObject* dict, SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence); SET_DICT_FROM_SIZE(real_length_key, n_members); SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members); + + // Prepare and set __match_args__ + Py_ssize_t i, k; + PyObject* keys = PyTuple_New(desc->n_in_sequence); + if (keys == NULL) { + return -1; + } + + for (i = k = 0; i < desc->n_in_sequence; ++i) { + if (desc->fields[i].name == PyStructSequence_UnnamedField) { + continue; + } + PyObject* new_member = PyUnicode_FromString(desc->fields[i].name); + if (new_member == NULL) { + goto error; + } + PyTuple_SET_ITEM(keys, k, new_member); + k++; + } + + if (_PyTuple_Resize(&keys, k) == -1) { + goto error; + } + + if (PyDict_SetItemString(dict, match_args_key, keys) < 0) { + goto error; + } + + Py_DECREF(keys); return 0; + +error: + Py_DECREF(keys); + return -1; } static void @@ -382,8 +460,10 @@ initialize_members(PyStructSequence_Desc *desc, PyMemberDef* members, members[k].name = NULL; } + int -PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) +_PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc, + unsigned long tp_flags) { PyMemberDef *members; Py_ssize_t n_members, n_unnamed_members; @@ -411,7 +491,7 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) type->tp_base = &PyTuple_Type; type->tp_methods = structseq_methods; type->tp_new = structseq_new; - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC; + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | tp_flags; type->tp_traverse = (traverseproc) structseq_traverse; n_members = count_members(desc, &n_unnamed_members); @@ -424,14 +504,14 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) type->tp_members = members; if (PyType_Ready(type) < 0) { - PyMem_FREE(members); + PyMem_Free(members); return -1; } Py_INCREF(type); if (initialize_structseq_dict( desc, type->tp_dict, n_members, n_unnamed_members) < 0) { - PyMem_FREE(members); + PyMem_Free(members); Py_DECREF(type); return -1; } @@ -439,6 +519,12 @@ PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) return 0; } +int +PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) +{ + return _PyStructSequence_InitType(type, desc, 0); +} + void PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) { @@ -449,7 +535,6 @@ PyTypeObject * PyStructSequence_NewType(PyStructSequence_Desc *desc) { PyMemberDef *members; - PyObject *bases; PyTypeObject *type; PyType_Slot slots[8]; PyType_Spec spec; @@ -467,17 +552,12 @@ PyStructSequence_NewType(PyStructSequence_Desc *desc) /* Initialize Slots */ slots[0] = (PyType_Slot){Py_tp_dealloc, (destructor)structseq_dealloc}; slots[1] = (PyType_Slot){Py_tp_repr, (reprfunc)structseq_repr}; - slots[2] = (PyType_Slot){Py_tp_methods, structseq_methods}; - slots[3] = (PyType_Slot){Py_tp_new, structseq_new}; - slots[4] = (PyType_Slot){Py_tp_members, members}; - slots[5] = (PyType_Slot){Py_tp_traverse, (traverseproc)structseq_traverse}; - if (desc->doc) { - slots[6] = (PyType_Slot){Py_tp_doc, (void *)desc->doc}; - slots[7] = (PyType_Slot){0, 0}; - } - else { - slots[6] = (PyType_Slot){0, 0}; - } + slots[2] = (PyType_Slot){Py_tp_doc, (void *)desc->doc}; + slots[3] = (PyType_Slot){Py_tp_methods, structseq_methods}; + slots[4] = (PyType_Slot){Py_tp_new, structseq_new}; + slots[5] = (PyType_Slot){Py_tp_members, members}; + slots[6] = (PyType_Slot){Py_tp_traverse, (traverseproc)structseq_traverse}; + slots[7] = (PyType_Slot){0, 0}; /* Initialize Spec */ /* The name in this PyType_Spec is statically allocated so it is */ @@ -488,14 +568,8 @@ PyStructSequence_NewType(PyStructSequence_Desc *desc) spec.flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC; spec.slots = slots; - bases = PyTuple_Pack(1, &PyTuple_Type); - if (bases == NULL) { - PyMem_FREE(members); - return NULL; - } - type = (PyTypeObject *)PyType_FromSpecWithBases(&spec, bases); - Py_DECREF(bases); - PyMem_FREE(members); + type = (PyTypeObject *)PyType_FromSpecWithBases(&spec, (PyObject *)&PyTuple_Type); + PyMem_Free(members); if (type == NULL) { return NULL; } @@ -514,7 +588,8 @@ int _PyStructSequence_Init(void) if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL || _PyUnicode_FromId(&PyId_n_fields) == NULL || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL) + { return -1; - + } return 0; } diff --git a/contrib/tools/python3/src/Objects/tupleobject.c b/contrib/tools/python3/src/Objects/tupleobject.c index 9092c9f8be..6b1ab74012 100644 --- a/contrib/tools/python3/src/Objects/tupleobject.c +++ b/contrib/tools/python3/src/Objects/tupleobject.c @@ -2,10 +2,10 @@ /* Tuple object implementation */ #include "Python.h" -#include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_accu.h" -#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() -#include "pycore_object.h" +#include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED() +#include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_object.h" // _PyObject_GC_TRACK() /*[clinic input] class tuple "PyTupleObject *" "&PyTuple_Type" @@ -14,41 +14,36 @@ class tuple "PyTupleObject *" "&PyTuple_Type" #include "clinic/tupleobject.c.h" -/* Speed optimization to avoid frequent malloc/free of small tuples */ -#ifndef PyTuple_MAXSAVESIZE -#define PyTuple_MAXSAVESIZE 20 /* Largest tuple to save on free list */ -#endif -#ifndef PyTuple_MAXFREELIST -#define PyTuple_MAXFREELIST 2000 /* Maximum number of tuples of each size to save */ -#endif #if PyTuple_MAXSAVESIZE > 0 -/* Entries 1 up to PyTuple_MAXSAVESIZE are free lists, entry 0 is the empty - tuple () of which at most one instance will be allocated. -*/ -static PyTupleObject *free_list[PyTuple_MAXSAVESIZE]; -static int numfree[PyTuple_MAXSAVESIZE]; +static struct _Py_tuple_state * +get_tuple_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->tuple; +} #endif + static inline void tuple_gc_track(PyTupleObject *op) { _PyObject_GC_TRACK(op); } + /* Print summary info about the state of the optimized allocator */ void _PyTuple_DebugMallocStats(FILE *out) { #if PyTuple_MAXSAVESIZE > 0 - int i; - char buf[128]; - for (i = 1; i < PyTuple_MAXSAVESIZE; i++) { + struct _Py_tuple_state *state = get_tuple_state(); + for (int i = 1; i < PyTuple_MAXSAVESIZE; i++) { + char buf[128]; PyOS_snprintf(buf, sizeof(buf), "free %d-sized PyTupleObject", i); - _PyDebugAllocatorStats(out, - buf, - numfree[i], _PyObject_VAR_SIZE(&PyTuple_Type, i)); + _PyDebugAllocatorStats(out, buf, state->numfree[i], + _PyObject_VAR_SIZE(&PyTuple_Type, i)); } #endif } @@ -65,19 +60,30 @@ static PyTupleObject * tuple_alloc(Py_ssize_t size) { PyTupleObject *op; +#if PyTuple_MAXSAVESIZE > 0 + // If Python is built with the empty tuple singleton, + // tuple_alloc(0) must not be called. + assert(size != 0); +#endif if (size < 0) { PyErr_BadInternalCall(); return NULL; } + #if PyTuple_MAXSAVESIZE > 0 - if (size < PyTuple_MAXSAVESIZE && (op = free_list[size]) != NULL) { + struct _Py_tuple_state *state = get_tuple_state(); +#ifdef Py_DEBUG + // tuple_alloc() must not be called after _PyTuple_Fini() + assert(state->numfree[0] != -1); +#endif + if (size < PyTuple_MAXSAVESIZE && (op = state->free_list[size]) != NULL) { assert(size != 0); - free_list[size] = (PyTupleObject *) op->ob_item[0]; - numfree[size]--; - /* Inline PyObject_InitVar */ + state->free_list[size] = (PyTupleObject *) op->ob_item[0]; + state->numfree[size]--; + /* Inlined _PyObject_InitVar() without _PyType_HasFeature() test */ #ifdef Py_TRACE_REFS - Py_SIZE(op) = size; - Py_TYPE(op) = &PyTuple_Type; + Py_SET_SIZE(op, size); + Py_SET_TYPE(op, &PyTuple_Type); #endif _Py_NewReference((PyObject *)op); } @@ -96,15 +102,56 @@ tuple_alloc(Py_ssize_t size) return op; } +static int +tuple_create_empty_tuple_singleton(struct _Py_tuple_state *state) +{ +#if PyTuple_MAXSAVESIZE > 0 + assert(state->free_list[0] == NULL); + + PyTupleObject *op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, 0); + if (op == NULL) { + return -1; + } + // The empty tuple singleton is not tracked by the GC. + // It does not contain any Python object. + + state->free_list[0] = op; + state->numfree[0]++; + + assert(state->numfree[0] == 1); +#endif + return 0; +} + + +static PyObject * +tuple_get_empty(void) +{ +#if PyTuple_MAXSAVESIZE > 0 + struct _Py_tuple_state *state = get_tuple_state(); + PyTupleObject *op = state->free_list[0]; + // tuple_get_empty() must not be called before _PyTuple_Init() + // or after _PyTuple_Fini() + assert(op != NULL); +#ifdef Py_DEBUG + assert(state->numfree[0] != -1); +#endif + + Py_INCREF(op); + return (PyObject *) op; +#else + return PyTuple_New(0); +#endif +} + + PyObject * PyTuple_New(Py_ssize_t size) { PyTupleObject *op; #if PyTuple_MAXSAVESIZE > 0 - if (size == 0 && free_list[0]) { - op = free_list[0]; - Py_INCREF(op); - return (PyObject *) op; + if (size == 0) { + return tuple_get_empty(); } #endif op = tuple_alloc(size); @@ -114,13 +161,6 @@ PyTuple_New(Py_ssize_t size) for (Py_ssize_t i = 0; i < size; i++) { op->ob_item[i] = NULL; } -#if PyTuple_MAXSAVESIZE > 0 - if (size == 0) { - free_list[0] = op; - ++numfree[0]; - Py_INCREF(op); /* extra INCREF so that this is never freed */ - } -#endif tuple_gc_track(op); return (PyObject *) op; } @@ -201,7 +241,7 @@ PyTuple_Pack(Py_ssize_t n, ...) va_list vargs; if (n == 0) { - return PyTuple_New(0); + return tuple_get_empty(); } va_start(vargs, n); @@ -227,27 +267,33 @@ PyTuple_Pack(Py_ssize_t n, ...) static void tupledealloc(PyTupleObject *op) { - Py_ssize_t i; Py_ssize_t len = Py_SIZE(op); PyObject_GC_UnTrack(op); Py_TRASHCAN_BEGIN(op, tupledealloc) if (len > 0) { - i = len; - while (--i >= 0) + Py_ssize_t i = len; + while (--i >= 0) { Py_XDECREF(op->ob_item[i]); + } #if PyTuple_MAXSAVESIZE > 0 - if (len < PyTuple_MAXSAVESIZE && - numfree[len] < PyTuple_MAXFREELIST && - Py_IS_TYPE(op, &PyTuple_Type)) + struct _Py_tuple_state *state = get_tuple_state(); +#ifdef Py_DEBUG + // tupledealloc() must not be called after _PyTuple_Fini() + assert(state->numfree[0] != -1); +#endif + if (len < PyTuple_MAXSAVESIZE + && state->numfree[len] < PyTuple_MAXFREELIST + && Py_IS_TYPE(op, &PyTuple_Type)) { - op->ob_item[0] = (PyObject *) free_list[len]; - numfree[len]++; - free_list[len] = op; + op->ob_item[0] = (PyObject *) state->free_list[len]; + state->numfree[len]++; + state->free_list[len] = op; goto done; /* return */ } #endif } Py_TYPE(op)->tp_free((PyObject *)op); + #if PyTuple_MAXSAVESIZE > 0 done: #endif @@ -414,7 +460,7 @@ PyObject * _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) { if (n == 0) { - return PyTuple_New(0); + return tuple_get_empty(); } PyTupleObject *tuple = tuple_alloc(n); @@ -475,16 +521,16 @@ tupleconcat(PyTupleObject *a, PyObject *bb) Py_TYPE(bb)->tp_name); return NULL; } -#define b ((PyTupleObject *)bb) + PyTupleObject *b = (PyTupleObject *)bb; + if (Py_SIZE(b) == 0 && PyTuple_CheckExact(a)) { Py_INCREF(a); return (PyObject *)a; } - if (Py_SIZE(a) > PY_SSIZE_T_MAX - Py_SIZE(b)) - return PyErr_NoMemory(); + assert((size_t)Py_SIZE(a) + (size_t)Py_SIZE(b) < PY_SSIZE_T_MAX); size = Py_SIZE(a) + Py_SIZE(b); if (size == 0) { - return PyTuple_New(0); + return tuple_get_empty(); } np = tuple_alloc(size); @@ -507,7 +553,6 @@ tupleconcat(PyTupleObject *a, PyObject *bb) } tuple_gc_track(np); return (PyObject *)np; -#undef b } static PyObject * @@ -526,7 +571,7 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n) } } if (Py_SIZE(a) == 0 || n <= 0) { - return PyTuple_New(0); + return tuple_get_empty(); } if (n > PY_SSIZE_T_MAX / Py_SIZE(a)) return PyErr_NoMemory(); @@ -702,10 +747,12 @@ tuple_new_impl(PyTypeObject *type, PyObject *iterable) if (type != &PyTuple_Type) return tuple_subtype_new(type, iterable); - if (iterable == NULL) - return PyTuple_New(0); - else + if (iterable == NULL) { + return tuple_get_empty(); + } + else { return PySequence_Tuple(iterable); + } } static PyObject * @@ -724,7 +771,9 @@ tuple_vectorcall(PyObject *type, PyObject * const*args, if (nargs) { return tuple_new_impl((PyTypeObject *)type, args[0]); } - return PyTuple_New(0); + else { + return tuple_get_empty(); + } } static PyObject * @@ -787,7 +836,7 @@ tuplesubscript(PyTupleObject* self, PyObject* item) &stop, step); if (slicelength <= 0) { - return PyTuple_New(0); + return tuple_get_empty(); } else if (start == 0 && step == 1 && slicelength == PyTuple_GET_SIZE(self) && @@ -868,7 +917,8 @@ PyTypeObject PyTuple_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS, /* tp_flags */ + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_TUPLE_SUBCLASS | + _Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE, /* tp_flags */ tuple_new__doc__, /* tp_doc */ (traverseproc)tupletraverse, /* tp_traverse */ 0, /* tp_clear */ @@ -958,13 +1008,14 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize) } void -_PyTuple_ClearFreeList(void) +_PyTuple_ClearFreeList(PyInterpreterState *interp) { #if PyTuple_MAXSAVESIZE > 0 + struct _Py_tuple_state *state = &interp->tuple; for (Py_ssize_t i = 1; i < PyTuple_MAXSAVESIZE; i++) { - PyTupleObject *p = free_list[i]; - free_list[i] = NULL; - numfree[i] = 0; + PyTupleObject *p = state->free_list[i]; + state->free_list[i] = NULL; + state->numfree[i] = 0; while (p) { PyTupleObject *q = p; p = (PyTupleObject *)(p->ob_item[0]); @@ -975,15 +1026,30 @@ _PyTuple_ClearFreeList(void) #endif } + +PyStatus +_PyTuple_Init(PyInterpreterState *interp) +{ + struct _Py_tuple_state *state = &interp->tuple; + if (tuple_create_empty_tuple_singleton(state) < 0) { + return _PyStatus_NO_MEMORY(); + } + return _PyStatus_OK(); +} + + void -_PyTuple_Fini(void) +_PyTuple_Fini(PyInterpreterState *interp) { #if PyTuple_MAXSAVESIZE > 0 - /* empty tuples are used all over the place and applications may - * rely on the fact that an empty tuple is a singleton. */ - Py_CLEAR(free_list[0]); - - _PyTuple_ClearFreeList(); + struct _Py_tuple_state *state = &interp->tuple; + // The empty tuple singleton must not be tracked by the GC + assert(!_PyObject_GC_IS_TRACKED(state->free_list[0])); + Py_CLEAR(state->free_list[0]); + _PyTuple_ClearFreeList(interp); +#ifdef Py_DEBUG + state->numfree[0] = -1; +#endif #endif } diff --git a/contrib/tools/python3/src/Objects/typeobject.c b/contrib/tools/python3/src/Objects/typeobject.c index cb0bb46145..b3ba1208eb 100644 --- a/contrib/tools/python3/src/Objects/typeobject.c +++ b/contrib/tools/python3/src/Objects/typeobject.c @@ -2,10 +2,13 @@ #include "Python.h" #include "pycore_call.h" +#include "pycore_compile.h" // _Py_Mangle() #include "pycore_initconfig.h" +#include "pycore_moduleobject.h" // _PyModule_GetDef() #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_unionobject.h" // _Py_union_type_or #include "frameobject.h" #include "structmember.h" // PyMemberDef @@ -19,53 +22,45 @@ class object "PyObject *" "&PyBaseObject_Type" #include "clinic/typeobject.c.h" -#define MCACHE - -#ifdef MCACHE -/* Support type attribute cache */ +/* Support type attribute lookup cache */ /* The cache can keep references to the names alive for longer than they normally would. This is why the maximum size is limited to MCACHE_MAX_ATTR_SIZE, since it might be a problem if very large strings are used as attribute names. */ #define MCACHE_MAX_ATTR_SIZE 100 -#define MCACHE_SIZE_EXP 12 #define MCACHE_HASH(version, name_hash) \ (((unsigned int)(version) ^ (unsigned int)(name_hash)) \ & ((1 << MCACHE_SIZE_EXP) - 1)) #define MCACHE_HASH_METHOD(type, name) \ - MCACHE_HASH((type)->tp_version_tag, \ - ((PyASCIIObject *)(name))->hash) + MCACHE_HASH((type)->tp_version_tag, ((Py_ssize_t)(name)) >> 3) #define MCACHE_CACHEABLE_NAME(name) \ PyUnicode_CheckExact(name) && \ PyUnicode_IS_READY(name) && \ - PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE - -struct method_cache_entry { - unsigned int version; - PyObject *name; /* reference to exactly a str or None */ - PyObject *value; /* borrowed */ -}; + (PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE) -static struct method_cache_entry method_cache[1 << MCACHE_SIZE_EXP]; +// bpo-42745: next_version_tag remains shared by all interpreters because of static types +// Used to set PyTypeObject.tp_version_tag static unsigned int next_version_tag = 0; -#endif -#define MCACHE_STATS 0 +typedef struct PySlot_Offset { + short subslot_offset; + short slot_offset; +} PySlot_Offset; -#if MCACHE_STATS -static size_t method_cache_hits = 0; -static size_t method_cache_misses = 0; -static size_t method_cache_collisions = 0; -#endif -#define INTERN_NAME_STRINGS +/* bpo-40521: Interned strings are shared by all subinterpreters */ +#ifndef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS +# define INTERN_NAME_STRINGS +#endif /* alphabetical order */ _Py_IDENTIFIER(__abstractmethods__); +_Py_IDENTIFIER(__annotations__); _Py_IDENTIFIER(__class__); _Py_IDENTIFIER(__class_getitem__); +_Py_IDENTIFIER(__classcell__); _Py_IDENTIFIER(__delitem__); _Py_IDENTIFIER(__dict__); _Py_IDENTIFIER(__doc__); @@ -77,8 +72,10 @@ _Py_IDENTIFIER(__len__); _Py_IDENTIFIER(__module__); _Py_IDENTIFIER(__name__); _Py_IDENTIFIER(__new__); +_Py_IDENTIFIER(__qualname__); _Py_IDENTIFIER(__set_name__); _Py_IDENTIFIER(__setitem__); +_Py_IDENTIFIER(__weakref__); _Py_IDENTIFIER(builtins); _Py_IDENTIFIER(mro); @@ -166,6 +163,11 @@ _PyType_CheckConsistency(PyTypeObject *type) CHECK(!(type->tp_flags & Py_TPFLAGS_READYING)); CHECK(type->tp_dict != NULL); + if (type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION) { + CHECK(type->tp_new == NULL); + CHECK(_PyDict_ContainsId(type->tp_dict, &PyId___new__) == 0); + } + return 1; #undef CHECK } @@ -217,46 +219,99 @@ _PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_d return PyUnicode_FromStringAndSize(start, end - start); } -unsigned int -PyType_ClearCache(void) + +static struct type_cache* +get_type_cache(void) { -#ifdef MCACHE - Py_ssize_t i; - unsigned int cur_version_tag = next_version_tag - 1; + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->type_cache; +} + + +static void +type_cache_clear(struct type_cache *cache, int use_none) +{ + for (Py_ssize_t i = 0; i < (1 << MCACHE_SIZE_EXP); i++) { + struct type_cache_entry *entry = &cache->hashtable[i]; + entry->version = 0; + if (use_none) { + // Set to None so _PyType_Lookup() can use Py_SETREF(), + // rather than using slower Py_XSETREF(). + Py_XSETREF(entry->name, Py_NewRef(Py_None)); + } + else { + Py_CLEAR(entry->name); + } + entry->value = NULL; + } + + // Mark all version tags as invalid + PyType_Modified(&PyBaseObject_Type); +} + + +void +_PyType_InitCache(PyInterpreterState *interp) +{ + struct type_cache *cache = &interp->type_cache; + for (Py_ssize_t i = 0; i < (1 << MCACHE_SIZE_EXP); i++) { + struct type_cache_entry *entry = &cache->hashtable[i]; + assert(entry->name == NULL); + + entry->version = 0; + // Set to None so _PyType_Lookup() can use Py_SETREF(), + // rather than using slower Py_XSETREF(). + entry->name = Py_NewRef(Py_None); + entry->value = NULL; + } +} + +static unsigned int +_PyType_ClearCache(PyInterpreterState *interp) +{ + struct type_cache *cache = &interp->type_cache; #if MCACHE_STATS - size_t total = method_cache_hits + method_cache_collisions + method_cache_misses; + size_t total = cache->hits + cache->collisions + cache->misses; fprintf(stderr, "-- Method cache hits = %zd (%d%%)\n", - method_cache_hits, (int) (100.0 * method_cache_hits / total)); + cache->hits, (int) (100.0 * cache->hits / total)); fprintf(stderr, "-- Method cache true misses = %zd (%d%%)\n", - method_cache_misses, (int) (100.0 * method_cache_misses / total)); + cache->misses, (int) (100.0 * cache->misses / total)); fprintf(stderr, "-- Method cache collisions = %zd (%d%%)\n", - method_cache_collisions, (int) (100.0 * method_cache_collisions / total)); + cache->collisions, (int) (100.0 * cache->collisions / total)); fprintf(stderr, "-- Method cache size = %zd KiB\n", - sizeof(method_cache) / 1024); + sizeof(cache->hashtable) / 1024); #endif - for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) { - method_cache[i].version = 0; - Py_CLEAR(method_cache[i].name); - method_cache[i].value = NULL; + unsigned int cur_version_tag = next_version_tag - 1; + if (_Py_IsMainInterpreter(interp)) { + next_version_tag = 0; } - next_version_tag = 0; - /* mark all version tags as invalid */ - PyType_Modified(&PyBaseObject_Type); + + type_cache_clear(cache, 0); + return cur_version_tag; -#else - return 0; -#endif } + +unsigned int +PyType_ClearCache(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return _PyType_ClearCache(interp); +} + + void -_PyType_Fini(void) +_PyType_Fini(PyInterpreterState *interp) { - PyType_ClearCache(); - clear_slotdefs(); + _PyType_ClearCache(interp); + if (_Py_IsMainInterpreter(interp)) { + clear_slotdefs(); + } } + void PyType_Modified(PyTypeObject *type) { @@ -266,10 +321,6 @@ PyType_Modified(PyTypeObject *type) Invariants: - - Py_TPFLAGS_VALID_VERSION_TAG is never set if - Py_TPFLAGS_HAVE_VERSION_TAG is not set (in case of a - bizarre MRO, see type_mro_modified()). - - before Py_TPFLAGS_VALID_VERSION_TAG can be set on a type, it must first be set on all super types. @@ -298,6 +349,7 @@ PyType_Modified(PyTypeObject *type) } } type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; + type->tp_version_tag = 0; /* 0 is not a valid version tag */ } static void @@ -320,9 +372,6 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) { PyObject *mro_meth = NULL; PyObject *type_mro_meth = NULL; - if (!_PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG)) - return; - if (custom) { mro_meth = lookup_maybe_method( (PyObject *)type, &PyId_mro, &unbound); @@ -345,8 +394,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) { assert(PyType_Check(b)); cls = (PyTypeObject *)b; - if (!_PyType_HasFeature(cls, Py_TPFLAGS_HAVE_VERSION_TAG) || - !PyType_IsSubtype(type, cls)) { + if (!PyType_IsSubtype(type, cls)) { goto clear; } } @@ -354,13 +402,12 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) { clear: Py_XDECREF(mro_meth); Py_XDECREF(type_mro_meth); - type->tp_flags &= ~(Py_TPFLAGS_HAVE_VERSION_TAG| - Py_TPFLAGS_VALID_VERSION_TAG); + type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG; + type->tp_version_tag = 0; /* 0 is not a valid version tag */ } -#ifdef MCACHE static int -assign_version_tag(PyTypeObject *type) +assign_version_tag(struct type_cache *cache, PyTypeObject *type) { /* Ensure that the tp_version_tag is valid and set Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this @@ -372,8 +419,6 @@ assign_version_tag(PyTypeObject *type) if (_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) return 1; - if (!_PyType_HasFeature(type, Py_TPFLAGS_HAVE_VERSION_TAG)) - return 0; if (!_PyType_HasFeature(type, Py_TPFLAGS_READY)) return 0; @@ -381,31 +426,22 @@ assign_version_tag(PyTypeObject *type) /* for stress-testing: next_version_tag &= 0xFF; */ if (type->tp_version_tag == 0) { - /* wrap-around or just starting Python - clear the whole - cache by filling names with references to Py_None. - Values are also set to NULL for added protection, as they - are borrowed reference */ - for (i = 0; i < (1 << MCACHE_SIZE_EXP); i++) { - method_cache[i].value = NULL; - Py_INCREF(Py_None); - Py_XSETREF(method_cache[i].name, Py_None); - } - /* mark all version tags as invalid */ - PyType_Modified(&PyBaseObject_Type); - return 1; + // Wrap-around or just starting Python - clear the whole cache + type_cache_clear(cache, 1); + return 0; } + bases = type->tp_bases; n = PyTuple_GET_SIZE(bases); for (i = 0; i < n; i++) { PyObject *b = PyTuple_GET_ITEM(bases, i); assert(PyType_Check(b)); - if (!assign_version_tag((PyTypeObject *)b)) + if (!assign_version_tag(cache, (PyTypeObject *)b)) return 0; } type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG; return 1; } -#endif static PyMemberDef type_members[] = { @@ -424,14 +460,16 @@ static PyMemberDef type_members[] = { static int check_set_special_type_attr(PyTypeObject *type, PyObject *value, const char *name) { - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) { PyErr_Format(PyExc_TypeError, - "can't set %s.%s", type->tp_name, name); + "cannot set '%s' attribute of immutable type '%s'", + name, type->tp_name); return 0; } if (!value) { PyErr_Format(PyExc_TypeError, - "can't delete %s.%s", type->tp_name, name); + "cannot delete '%s' attribute of immutable type '%s'", + name, type->tp_name); return 0; } @@ -894,6 +932,75 @@ type_set_doc(PyTypeObject *type, PyObject *value, void *context) return _PyDict_SetItemId(type->tp_dict, &PyId___doc__, value); } +static PyObject * +type_get_annotations(PyTypeObject *type, void *context) +{ + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + PyErr_Format(PyExc_AttributeError, "type object '%s' has no attribute '__annotations__'", type->tp_name); + return NULL; + } + + PyObject *annotations; + /* there's no _PyDict_GetItemId without WithError, so let's LBYL. */ + if (_PyDict_ContainsId(type->tp_dict, &PyId___annotations__)) { + annotations = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___annotations__); + /* + ** _PyDict_GetItemIdWithError could still fail, + ** for instance with a well-timed Ctrl-C or a MemoryError. + ** so let's be totally safe. + */ + if (annotations) { + if (Py_TYPE(annotations)->tp_descr_get) { + annotations = Py_TYPE(annotations)->tp_descr_get(annotations, NULL, + (PyObject *)type); + } else { + Py_INCREF(annotations); + } + } + } else { + annotations = PyDict_New(); + if (annotations) { + int result = _PyDict_SetItemId(type->tp_dict, &PyId___annotations__, annotations); + if (result) { + Py_CLEAR(annotations); + } else { + PyType_Modified(type); + } + } + } + return annotations; +} + +static int +type_set_annotations(PyTypeObject *type, PyObject *value, void *context) +{ + if (_PyType_HasFeature(type, Py_TPFLAGS_IMMUTABLETYPE)) { + PyErr_Format(PyExc_TypeError, + "cannot set '__annotations__' attribute of immutable type '%s'", + type->tp_name); + return -1; + } + + int result; + if (value != NULL) { + /* set */ + result = _PyDict_SetItemId(type->tp_dict, &PyId___annotations__, value); + } else { + /* delete */ + if (!_PyDict_ContainsId(type->tp_dict, &PyId___annotations__)) { + PyErr_Format(PyExc_AttributeError, "__annotations__"); + return -1; + } + result = _PyDict_DelItemId(type->tp_dict, &PyId___annotations__); + } + + if (result == 0) { + PyType_Modified(type); + } + return result; +} + + /*[clinic input] type.__instancecheck__ -> bool @@ -937,6 +1044,7 @@ static PyGetSetDef type_getsets[] = { {"__dict__", (getter)type_dict, NULL, NULL}, {"__doc__", (getter)type_get_doc, (setter)type_set_doc, NULL}, {"__text_signature__", (getter)type_get_text_signature, NULL, NULL}, + {"__annotations__", (getter)type_get_annotations, (setter)type_set_annotations, NULL}, {0} }; @@ -1006,8 +1114,7 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) if (type->tp_new == NULL) { _PyErr_Format(tstate, PyExc_TypeError, - "cannot create '%.100s' instances", - type->tp_name); + "cannot create '%s' instances", type->tp_name); return NULL; } @@ -1047,7 +1154,7 @@ PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems) obj = _PyObject_GC_Malloc(size); } else { - obj = (PyObject *)PyObject_MALLOC(size); + obj = (PyObject *)PyObject_Malloc(size); } if (obj == NULL) { @@ -1057,10 +1164,10 @@ PyType_GenericAlloc(PyTypeObject *type, Py_ssize_t nitems) memset(obj, '\0', size); if (type->tp_itemsize == 0) { - (void)PyObject_INIT(obj, type); + _PyObject_Init(obj, type); } else { - (void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems); + _PyObject_InitVar((PyVarObject *)obj, type, nitems); } if (_PyType_IS_GC(type)) { @@ -1782,7 +1889,7 @@ pmerge(PyObject *acc, PyObject **to_merge, Py_ssize_t to_merge_size) } out: - PyMem_Del(remain); + PyMem_Free(remain); return res; } @@ -1795,7 +1902,7 @@ mro_implementation(PyTypeObject *type) PyObject **to_merge; Py_ssize_t i, n; - if (type->tp_dict == NULL) { + if (!_PyType_IsReady(type)) { if (PyType_Ready(type) < 0) return NULL; } @@ -1862,7 +1969,7 @@ mro_implementation(PyTypeObject *type) result = PyList_New(1); if (result == NULL) { - PyMem_Del(to_merge); + PyMem_Free(to_merge); return NULL; } @@ -1872,7 +1979,7 @@ mro_implementation(PyTypeObject *type) Py_CLEAR(result); } - PyMem_Del(to_merge); + PyMem_Free(to_merge); return result; } @@ -1967,14 +2074,20 @@ mro_invoke(PyTypeObject *type) new_mro = PySequence_Tuple(mro_result); Py_DECREF(mro_result); - if (new_mro == NULL) + if (new_mro == NULL) { return NULL; + } - if (custom && mro_check(type, new_mro) < 0) { + if (PyTuple_GET_SIZE(new_mro) == 0) { Py_DECREF(new_mro); + PyErr_Format(PyExc_TypeError, "type MRO must not be empty"); return NULL; } + if (custom && mro_check(type, new_mro) < 0) { + Py_DECREF(new_mro); + return NULL; + } return new_mro; } @@ -2014,8 +2127,9 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro) new_mro = mro_invoke(type); /* might cause reentrance */ reent = (type->tp_mro != old_mro); Py_XDECREF(old_mro); - if (new_mro == NULL) + if (new_mro == NULL) { return -1; + } if (reent) { Py_DECREF(new_mro); @@ -2064,7 +2178,7 @@ best_base(PyObject *bases) return NULL; } base_i = (PyTypeObject *)base_proto; - if (base_i->tp_dict == NULL) { + if (!_PyType_IsReady(base_i)) { if (PyType_Ready(base_i) < 0) return NULL; } @@ -2141,8 +2255,8 @@ static void object_dealloc(PyObject *); static int object_init(PyObject *, PyObject *, PyObject *); static int update_slot(PyTypeObject *, PyObject *); static void fixup_slot_dispatchers(PyTypeObject *); -static int set_names(PyTypeObject *); -static int init_subclass(PyTypeObject *, PyObject *); +static int type_new_set_names(PyTypeObject *); +static int type_new_init_subclass(PyTypeObject *, PyObject *); /* * Helpers for __dict__ descriptor. We don't want to expose the dicts @@ -2387,398 +2501,467 @@ _PyType_CalculateMetaclass(PyTypeObject *metatype, PyObject *bases) return winner; } + +// Forward declaration static PyObject * -type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) -{ - PyObject *name, *bases = NULL, *orig_dict, *dict = NULL; - PyObject *qualname, *slots = NULL, *tmp, *newslots, *cell; - PyTypeObject *type = NULL, *base, *tmptype, *winner; - PyHeapTypeObject *et; - PyMemberDef *mp; - Py_ssize_t i, nbases, nslots, slotoffset, name_size; - int j, may_add_dict, may_add_weak, add_dict, add_weak; - _Py_IDENTIFIER(__qualname__); - _Py_IDENTIFIER(__slots__); - _Py_IDENTIFIER(__classcell__); +type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds); - assert(args != NULL && PyTuple_Check(args)); - assert(kwds == NULL || PyDict_Check(kwds)); +typedef struct { + PyTypeObject *metatype; + PyObject *args; + PyObject *kwds; + PyObject *orig_dict; + PyObject *name; + PyObject *bases; + PyTypeObject *base; + PyObject *slots; + Py_ssize_t nslot; + int add_dict; + int add_weak; + int may_add_dict; + int may_add_weak; +} type_new_ctx; - /* Check arguments: (name, bases, dict) */ - if (!PyArg_ParseTuple(args, "UO!O!:type.__new__", &name, &PyTuple_Type, - &bases, &PyDict_Type, &orig_dict)) - return NULL; - /* Adjust for empty tuple bases */ - nbases = PyTuple_GET_SIZE(bases); - if (nbases == 0) { - base = &PyBaseObject_Type; - bases = PyTuple_Pack(1, base); - if (bases == NULL) - return NULL; - nbases = 1; - } - else { - _Py_IDENTIFIER(__mro_entries__); - for (i = 0; i < nbases; i++) { - tmp = PyTuple_GET_ITEM(bases, i); - if (PyType_Check(tmp)) { - continue; - } - if (_PyObject_LookupAttrId(tmp, &PyId___mro_entries__, &tmp) < 0) { - return NULL; - } - if (tmp != NULL) { +/* Check for valid slot names and two special cases */ +static int +type_new_visit_slots(type_new_ctx *ctx) +{ + PyObject *slots = ctx->slots; + Py_ssize_t nslot = ctx->nslot; + for (Py_ssize_t i = 0; i < nslot; i++) { + PyObject *name = PyTuple_GET_ITEM(slots, i); + if (!valid_identifier(name)) { + return -1; + } + assert(PyUnicode_Check(name)); + if (_PyUnicode_EqualToASCIIId(name, &PyId___dict__)) { + if (!ctx->may_add_dict || ctx->add_dict != 0) { PyErr_SetString(PyExc_TypeError, - "type() doesn't support MRO entry resolution; " - "use types.new_class()"); - Py_DECREF(tmp); - return NULL; + "__dict__ slot disallowed: " + "we already got one"); + return -1; } + ctx->add_dict++; } - /* Search the bases for the proper metatype to deal with this: */ - winner = _PyType_CalculateMetaclass(metatype, bases); - if (winner == NULL) { - return NULL; + if (_PyUnicode_EqualToASCIIId(name, &PyId___weakref__)) { + if (!ctx->may_add_weak || ctx->add_weak != 0) { + PyErr_SetString(PyExc_TypeError, + "__weakref__ slot disallowed: " + "either we already got one, " + "or __itemsize__ != 0"); + return -1; + } + ctx->add_weak++; } + } + return 0; +} - if (winner != metatype) { - if (winner->tp_new != type_new) /* Pass it to the winner */ - return winner->tp_new(winner, args, kwds); - metatype = winner; - } - /* Calculate best base, and check that all bases are type objects */ - base = best_base(bases); - if (base == NULL) { - return NULL; - } +/* Copy slots into a list, mangle names and sort them. + Sorted names are needed for __class__ assignment. + Convert them back to tuple at the end. +*/ +static PyObject* +type_new_copy_slots(type_new_ctx *ctx, PyObject *dict) +{ + PyObject *slots = ctx->slots; + Py_ssize_t nslot = ctx->nslot; - Py_INCREF(bases); + Py_ssize_t new_nslot = nslot - ctx->add_dict - ctx->add_weak; + PyObject *new_slots = PyList_New(new_nslot); + if (new_slots == NULL) { + return NULL; } - /* Use "goto error" from this point on as we now own the reference to "bases". */ - - dict = PyDict_Copy(orig_dict); - if (dict == NULL) - goto error; - - /* Check for a __slots__ sequence variable in dict, and count it */ - slots = _PyDict_GetItemIdWithError(dict, &PyId___slots__); - nslots = 0; - add_dict = 0; - add_weak = 0; - may_add_dict = base->tp_dictoffset == 0; - may_add_weak = base->tp_weaklistoffset == 0 && base->tp_itemsize == 0; - if (slots == NULL) { - if (PyErr_Occurred()) { - goto error; - } - if (may_add_dict) { - add_dict++; - } - if (may_add_weak) { - add_weak++; + Py_ssize_t j = 0; + for (Py_ssize_t i = 0; i < nslot; i++) { + PyObject *slot = PyTuple_GET_ITEM(slots, i); + if ((ctx->add_dict && + _PyUnicode_EqualToASCIIId(slot, &PyId___dict__)) || + (ctx->add_weak && + _PyUnicode_EqualToASCIIString(slot, "__weakref__"))) + { + continue; } - } - else { - /* Have slots */ - /* Make it into a tuple */ - if (PyUnicode_Check(slots)) - slots = PyTuple_Pack(1, slots); - else - slots = PySequence_Tuple(slots); - if (slots == NULL) + slot =_Py_Mangle(ctx->name, slot); + if (!slot) { goto error; - assert(PyTuple_Check(slots)); + } + PyList_SET_ITEM(new_slots, j, slot); - /* Are slots allowed? */ - nslots = PyTuple_GET_SIZE(slots); - if (nslots > 0 && base->tp_itemsize != 0) { - PyErr_Format(PyExc_TypeError, - "nonempty __slots__ " - "not supported for subtype of '%s'", - base->tp_name); + int r = PyDict_Contains(dict, slot); + if (r < 0) { goto error; } - - /* Check for valid slot names and two special cases */ - for (i = 0; i < nslots; i++) { - PyObject *tmp = PyTuple_GET_ITEM(slots, i); - if (!valid_identifier(tmp)) + if (r > 0) { + /* CPython inserts __qualname__ and __classcell__ (when needed) + into the namespace when creating a class. They will be deleted + below so won't act as class variables. */ + if (!_PyUnicode_EqualToASCIIId(slot, &PyId___qualname__) && + !_PyUnicode_EqualToASCIIId(slot, &PyId___classcell__)) + { + PyErr_Format(PyExc_ValueError, + "%R in __slots__ conflicts with class variable", + slot); goto error; - assert(PyUnicode_Check(tmp)); - if (_PyUnicode_EqualToASCIIId(tmp, &PyId___dict__)) { - if (!may_add_dict || add_dict) { - PyErr_SetString(PyExc_TypeError, - "__dict__ slot disallowed: " - "we already got one"); - goto error; - } - add_dict++; - } - if (_PyUnicode_EqualToASCIIString(tmp, "__weakref__")) { - if (!may_add_weak || add_weak) { - PyErr_SetString(PyExc_TypeError, - "__weakref__ slot disallowed: " - "either we already got one, " - "or __itemsize__ != 0"); - goto error; - } - add_weak++; } } - /* Copy slots into a list, mangle names and sort them. - Sorted names are needed for __class__ assignment. - Convert them back to tuple at the end. - */ - newslots = PyList_New(nslots - add_dict - add_weak); - if (newslots == NULL) - goto error; - for (i = j = 0; i < nslots; i++) { - tmp = PyTuple_GET_ITEM(slots, i); - if ((add_dict && - _PyUnicode_EqualToASCIIId(tmp, &PyId___dict__)) || - (add_weak && - _PyUnicode_EqualToASCIIString(tmp, "__weakref__"))) + j++; + } + assert(j == new_nslot); + + if (PyList_Sort(new_slots) == -1) { + goto error; + } + + PyObject *tuple = PyList_AsTuple(new_slots); + Py_DECREF(new_slots); + if (tuple == NULL) { + return NULL; + } + + assert(PyTuple_GET_SIZE(tuple) == new_nslot); + return tuple; + +error: + Py_DECREF(new_slots); + return NULL; +} + + +static void +type_new_slots_bases(type_new_ctx *ctx) +{ + Py_ssize_t nbases = PyTuple_GET_SIZE(ctx->bases); + if (nbases > 1 && + ((ctx->may_add_dict && ctx->add_dict == 0) || + (ctx->may_add_weak && ctx->add_weak == 0))) + { + for (Py_ssize_t i = 0; i < nbases; i++) { + PyObject *base = PyTuple_GET_ITEM(ctx->bases, i); + if (base == (PyObject *)ctx->base) { + /* Skip primary base */ continue; - tmp =_Py_Mangle(name, tmp); - if (!tmp) { - Py_DECREF(newslots); - goto error; } - PyList_SET_ITEM(newslots, j, tmp); - if (PyDict_GetItemWithError(dict, tmp)) { - /* CPython inserts __qualname__ and __classcell__ (when needed) - into the namespace when creating a class. They will be deleted - below so won't act as class variables. */ - if (!_PyUnicode_EqualToASCIIId(tmp, &PyId___qualname__) && - !_PyUnicode_EqualToASCIIId(tmp, &PyId___classcell__)) { - PyErr_Format(PyExc_ValueError, - "%R in __slots__ conflicts with class variable", - tmp); - Py_DECREF(newslots); - goto error; - } + + assert(PyType_Check(base)); + PyTypeObject *type = (PyTypeObject *)base; + if (ctx->may_add_dict && ctx->add_dict == 0 && + type->tp_dictoffset != 0) + { + ctx->add_dict++; } - else if (PyErr_Occurred()) { - Py_DECREF(newslots); - goto error; + if (ctx->may_add_weak && ctx->add_weak == 0 && + type->tp_weaklistoffset != 0) + { + ctx->add_weak++; } - j++; - } - assert(j == nslots - add_dict - add_weak); - nslots = j; - Py_CLEAR(slots); - if (PyList_Sort(newslots) == -1) { - Py_DECREF(newslots); - goto error; + if (ctx->may_add_dict && ctx->add_dict == 0) { + continue; + } + if (ctx->may_add_weak && ctx->add_weak == 0) { + continue; + } + /* Nothing more to check */ + break; } - slots = PyList_AsTuple(newslots); - Py_DECREF(newslots); - if (slots == NULL) - goto error; + } +} - /* Secondary bases may provide weakrefs or dict */ - if (nbases > 1 && - ((may_add_dict && !add_dict) || - (may_add_weak && !add_weak))) { - for (i = 0; i < nbases; i++) { - tmp = PyTuple_GET_ITEM(bases, i); - if (tmp == (PyObject *)base) - continue; /* Skip primary base */ - assert(PyType_Check(tmp)); - tmptype = (PyTypeObject *)tmp; - if (may_add_dict && !add_dict && - tmptype->tp_dictoffset != 0) - add_dict++; - if (may_add_weak && !add_weak && - tmptype->tp_weaklistoffset != 0) - add_weak++; - if (may_add_dict && !add_dict) - continue; - if (may_add_weak && !add_weak) - continue; - /* Nothing more to check */ - break; - } + +static int +type_new_slots_impl(type_new_ctx *ctx, PyObject *dict) +{ + /* Are slots allowed? */ + if (ctx->nslot > 0 && ctx->base->tp_itemsize != 0) { + PyErr_Format(PyExc_TypeError, + "nonempty __slots__ not supported for subtype of '%s'", + ctx->base->tp_name); + return -1; + } + + if (type_new_visit_slots(ctx) < 0) { + return -1; + } + + PyObject *new_slots = type_new_copy_slots(ctx, dict); + if (new_slots == NULL) { + return -1; + } + assert(PyTuple_CheckExact(new_slots)); + + Py_XSETREF(ctx->slots, new_slots); + ctx->nslot = PyTuple_GET_SIZE(new_slots); + + /* Secondary bases may provide weakrefs or dict */ + type_new_slots_bases(ctx); + return 0; +} + + +static Py_ssize_t +type_new_slots(type_new_ctx *ctx, PyObject *dict) +{ + // Check for a __slots__ sequence variable in dict, and count it + ctx->add_dict = 0; + ctx->add_weak = 0; + ctx->may_add_dict = (ctx->base->tp_dictoffset == 0); + ctx->may_add_weak = (ctx->base->tp_weaklistoffset == 0 + && ctx->base->tp_itemsize == 0); + + if (ctx->slots == NULL) { + if (ctx->may_add_dict) { + ctx->add_dict++; + } + if (ctx->may_add_weak) { + ctx->add_weak++; } } + else { + /* Have slots */ + if (type_new_slots_impl(ctx, dict) < 0) { + return -1; + } + } + return 0; +} - /* Allocate the type object */ - type = (PyTypeObject *)metatype->tp_alloc(metatype, nslots); - if (type == NULL) - goto error; - /* Keep name and slots alive in the extended type object */ - et = (PyHeapTypeObject *)type; - Py_INCREF(name); - et->ht_name = name; - et->ht_slots = slots; - slots = NULL; +static PyTypeObject* +type_new_alloc(type_new_ctx *ctx) +{ + PyTypeObject *metatype = ctx->metatype; + PyTypeObject *type; - /* Initialize tp_flags */ + // Allocate the type object + type = (PyTypeObject *)metatype->tp_alloc(metatype, ctx->nslot); + if (type == NULL) { + return NULL; + } + PyHeapTypeObject *et = (PyHeapTypeObject *)type; + + // Initialize tp_flags. // All heap types need GC, since we can create a reference cycle by storing - // an instance on one of its parents: - type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | - Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC; + // an instance on one of its parents. + type->tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | + Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC); - /* Initialize essential fields */ + // Initialize essential fields type->tp_as_async = &et->as_async; type->tp_as_number = &et->as_number; type->tp_as_sequence = &et->as_sequence; type->tp_as_mapping = &et->as_mapping; type->tp_as_buffer = &et->as_buffer; - type->tp_name = PyUnicode_AsUTF8AndSize(name, &name_size); - if (!type->tp_name) - goto error; + + type->tp_bases = Py_NewRef(ctx->bases); + type->tp_base = (PyTypeObject *)Py_NewRef(ctx->base); + + type->tp_dealloc = subtype_dealloc; + /* Always override allocation strategy to use regular heap */ + type->tp_alloc = PyType_GenericAlloc; + type->tp_free = PyObject_GC_Del; + + type->tp_traverse = subtype_traverse; + type->tp_clear = subtype_clear; + + et->ht_name = Py_NewRef(ctx->name); + et->ht_module = NULL; + + return type; +} + + +static int +type_new_set_name(const type_new_ctx *ctx, PyTypeObject *type) +{ + Py_ssize_t name_size; + type->tp_name = PyUnicode_AsUTF8AndSize(ctx->name, &name_size); + if (!type->tp_name) { + return -1; + } if (strlen(type->tp_name) != (size_t)name_size) { PyErr_SetString(PyExc_ValueError, "type name must not contain null characters"); - goto error; + return -1; } + return 0; +} - /* Set tp_base and tp_bases */ - type->tp_bases = bases; - bases = NULL; - Py_INCREF(base); - type->tp_base = base; - /* Initialize tp_dict from passed-in dict */ - Py_INCREF(dict); - type->tp_dict = dict; +/* Set __module__ in the dict */ +static int +type_new_set_module(PyTypeObject *type) +{ + int r = _PyDict_ContainsId(type->tp_dict, &PyId___module__); + if (r < 0) { + return -1; + } + if (r > 0) { + return 0; + } - /* Set __module__ in the dict */ - if (_PyDict_GetItemIdWithError(dict, &PyId___module__) == NULL) { + PyObject *globals = PyEval_GetGlobals(); + if (globals == NULL) { + return 0; + } + + PyObject *module = _PyDict_GetItemIdWithError(globals, &PyId___name__); + if (module == NULL) { if (PyErr_Occurred()) { - goto error; - } - tmp = PyEval_GetGlobals(); - if (tmp != NULL) { - tmp = _PyDict_GetItemIdWithError(tmp, &PyId___name__); - if (tmp != NULL) { - if (_PyDict_SetItemId(dict, &PyId___module__, - tmp) < 0) - goto error; - } - else if (PyErr_Occurred()) { - goto error; - } + return -1; } + return 0; } - /* Set ht_qualname to dict['__qualname__'] if available, else to - __name__. The __qualname__ accessor will look for ht_qualname. - */ - qualname = _PyDict_GetItemIdWithError(dict, &PyId___qualname__); + if (_PyDict_SetItemId(type->tp_dict, &PyId___module__, module) < 0) { + return -1; + } + return 0; +} + + +/* Set ht_qualname to dict['__qualname__'] if available, else to + __name__. The __qualname__ accessor will look for ht_qualname. */ +static int +type_new_set_ht_name(PyTypeObject *type) +{ + PyHeapTypeObject *et = (PyHeapTypeObject *)type; + PyObject *qualname = _PyDict_GetItemIdWithError(type->tp_dict, + &PyId___qualname__); if (qualname != NULL) { if (!PyUnicode_Check(qualname)) { PyErr_Format(PyExc_TypeError, - "type __qualname__ must be a str, not %s", - Py_TYPE(qualname)->tp_name); - goto error; + "type __qualname__ must be a str, not %s", + Py_TYPE(qualname)->tp_name); + return -1; + } + et->ht_qualname = Py_NewRef(qualname); + if (_PyDict_DelItemId(type->tp_dict, &PyId___qualname__) < 0) { + return -1; } } - else if (PyErr_Occurred()) { - goto error; + else { + if (PyErr_Occurred()) { + return -1; + } + et->ht_qualname = Py_NewRef(et->ht_name); } - et->ht_qualname = qualname ? qualname : et->ht_name; - Py_INCREF(et->ht_qualname); - if (qualname != NULL && _PyDict_DelItemId(dict, &PyId___qualname__) < 0) - goto error; + return 0; +} - /* Set ht_module */ - et->ht_module = NULL; - /* Set tp_doc to a copy of dict['__doc__'], if the latter is there - and is a string. The __doc__ accessor will first look for tp_doc; - if that fails, it will still look into __dict__. - */ - { - PyObject *doc = _PyDict_GetItemIdWithError(dict, &PyId___doc__); - if (doc != NULL && PyUnicode_Check(doc)) { - Py_ssize_t len; - const char *doc_str; - char *tp_doc; - - doc_str = PyUnicode_AsUTF8(doc); - if (doc_str == NULL) - goto error; - /* Silently truncate the docstring if it contains null bytes. */ - len = strlen(doc_str); - tp_doc = (char *)PyObject_MALLOC(len + 1); - if (tp_doc == NULL) { - PyErr_NoMemory(); - goto error; - } - memcpy(tp_doc, doc_str, len + 1); - type->tp_doc = tp_doc; - } - else if (doc == NULL && PyErr_Occurred()) { - goto error; +/* Set tp_doc to a copy of dict['__doc__'], if the latter is there + and is a string. The __doc__ accessor will first look for tp_doc; + if that fails, it will still look into __dict__. */ +static int +type_new_set_doc(PyTypeObject *type) +{ + PyObject *doc = _PyDict_GetItemIdWithError(type->tp_dict, &PyId___doc__); + if (doc == NULL) { + if (PyErr_Occurred()) { + return -1; } + // no __doc__ key + return 0; + } + if (!PyUnicode_Check(doc)) { + // ignore non-string __doc__ + return 0; } - /* Special-case __new__: if it's a plain function, - make it a static function */ - tmp = _PyDict_GetItemIdWithError(dict, &PyId___new__); - if (tmp != NULL && PyFunction_Check(tmp)) { - tmp = PyStaticMethod_New(tmp); - if (tmp == NULL) - goto error; - if (_PyDict_SetItemId(dict, &PyId___new__, tmp) < 0) { - Py_DECREF(tmp); - goto error; - } - Py_DECREF(tmp); + const char *doc_str = PyUnicode_AsUTF8(doc); + if (doc_str == NULL) { + return -1; } - else if (tmp == NULL && PyErr_Occurred()) { - goto error; + + // Silently truncate the docstring if it contains a null byte + Py_ssize_t size = strlen(doc_str) + 1; + char *tp_doc = (char *)PyObject_Malloc(size); + if (tp_doc == NULL) { + PyErr_NoMemory(); + return -1; } - /* Special-case __init_subclass__ and __class_getitem__: - if they are plain functions, make them classmethods */ - tmp = _PyDict_GetItemIdWithError(dict, &PyId___init_subclass__); - if (tmp != NULL && PyFunction_Check(tmp)) { - tmp = PyClassMethod_New(tmp); - if (tmp == NULL) - goto error; - if (_PyDict_SetItemId(dict, &PyId___init_subclass__, tmp) < 0) { - Py_DECREF(tmp); - goto error; + memcpy(tp_doc, doc_str, size); + type->tp_doc = tp_doc; + return 0; +} + + +static int +type_new_staticmethod(PyTypeObject *type, _Py_Identifier *attr_id) +{ + PyObject *func = _PyDict_GetItemIdWithError(type->tp_dict, attr_id); + if (func == NULL) { + if (PyErr_Occurred()) { + return -1; } - Py_DECREF(tmp); + return 0; } - else if (tmp == NULL && PyErr_Occurred()) { - goto error; + if (!PyFunction_Check(func)) { + return 0; } - tmp = _PyDict_GetItemIdWithError(dict, &PyId___class_getitem__); - if (tmp != NULL && PyFunction_Check(tmp)) { - tmp = PyClassMethod_New(tmp); - if (tmp == NULL) - goto error; - if (_PyDict_SetItemId(dict, &PyId___class_getitem__, tmp) < 0) { - Py_DECREF(tmp); - goto error; + PyObject *static_func = PyStaticMethod_New(func); + if (static_func == NULL) { + return -1; + } + if (_PyDict_SetItemId(type->tp_dict, attr_id, static_func) < 0) { + Py_DECREF(static_func); + return -1; + } + Py_DECREF(static_func); + return 0; +} + + +static int +type_new_classmethod(PyTypeObject *type, _Py_Identifier *attr_id) +{ + PyObject *func = _PyDict_GetItemIdWithError(type->tp_dict, attr_id); + if (func == NULL) { + if (PyErr_Occurred()) { + return -1; } - Py_DECREF(tmp); + return 0; } - else if (tmp == NULL && PyErr_Occurred()) { - goto error; + if (!PyFunction_Check(func)) { + return 0; } - /* Add descriptors for custom slots from __slots__, or for __dict__ */ - mp = PyHeapType_GET_MEMBERS(et); - slotoffset = base->tp_basicsize; + PyObject *method = PyClassMethod_New(func); + if (method == NULL) { + return -1; + } + + if (_PyDict_SetItemId(type->tp_dict, attr_id, method) < 0) { + Py_DECREF(method); + return -1; + } + Py_DECREF(method); + return 0; +} + + +/* Add descriptors for custom slots from __slots__, or for __dict__ */ +static int +type_new_descriptors(const type_new_ctx *ctx, PyTypeObject *type) +{ + PyHeapTypeObject *et = (PyHeapTypeObject *)type; + Py_ssize_t slotoffset = ctx->base->tp_basicsize; if (et->ht_slots != NULL) { - for (i = 0; i < nslots; i++, mp++) { + PyMemberDef *mp = PyHeapType_GET_MEMBERS(et); + Py_ssize_t nslot = PyTuple_GET_SIZE(et->ht_slots); + for (Py_ssize_t i = 0; i < nslot; i++, mp++) { mp->name = PyUnicode_AsUTF8( PyTuple_GET_ITEM(et->ht_slots, i)); - if (mp->name == NULL) - goto error; + if (mp->name == NULL) { + return -1; + } mp->type = T_OBJECT_EX; mp->offset = slotoffset; @@ -2789,95 +2972,391 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) slotoffset += sizeof(PyObject *); } } - if (add_dict) { - if (base->tp_itemsize) + + if (ctx->add_dict) { + if (ctx->base->tp_itemsize) { type->tp_dictoffset = -(long)sizeof(PyObject *); - else + } + else { type->tp_dictoffset = slotoffset; + } slotoffset += sizeof(PyObject *); } - if (add_weak) { - assert(!base->tp_itemsize); + + if (ctx->add_weak) { + assert(!ctx->base->tp_itemsize); type->tp_weaklistoffset = slotoffset; slotoffset += sizeof(PyObject *); } + type->tp_basicsize = slotoffset; - type->tp_itemsize = base->tp_itemsize; + type->tp_itemsize = ctx->base->tp_itemsize; type->tp_members = PyHeapType_GET_MEMBERS(et); + return 0; +} + - if (type->tp_weaklistoffset && type->tp_dictoffset) +static void +type_new_set_slots(const type_new_ctx *ctx, PyTypeObject *type) +{ + if (type->tp_weaklistoffset && type->tp_dictoffset) { type->tp_getset = subtype_getsets_full; - else if (type->tp_weaklistoffset && !type->tp_dictoffset) + } + else if (type->tp_weaklistoffset && !type->tp_dictoffset) { type->tp_getset = subtype_getsets_weakref_only; - else if (!type->tp_weaklistoffset && type->tp_dictoffset) + } + else if (!type->tp_weaklistoffset && type->tp_dictoffset) { type->tp_getset = subtype_getsets_dict_only; - else + } + else { type->tp_getset = NULL; + } /* Special case some slots */ - if (type->tp_dictoffset != 0 || nslots > 0) { - if (base->tp_getattr == NULL && base->tp_getattro == NULL) + if (type->tp_dictoffset != 0 || ctx->nslot > 0) { + PyTypeObject *base = ctx->base; + if (base->tp_getattr == NULL && base->tp_getattro == NULL) { type->tp_getattro = PyObject_GenericGetAttr; - if (base->tp_setattr == NULL && base->tp_setattro == NULL) + } + if (base->tp_setattr == NULL && base->tp_setattro == NULL) { type->tp_setattro = PyObject_GenericSetAttr; + } } - type->tp_dealloc = subtype_dealloc; +} - /* Always override allocation strategy to use regular heap */ - type->tp_alloc = PyType_GenericAlloc; - type->tp_free = PyObject_GC_Del; - type->tp_traverse = subtype_traverse; - type->tp_clear = subtype_clear; - /* store type in class' cell if one is supplied */ - cell = _PyDict_GetItemIdWithError(dict, &PyId___classcell__); - if (cell != NULL) { - /* At least one method requires a reference to its defining class */ - if (!PyCell_Check(cell)) { - PyErr_Format(PyExc_TypeError, - "__classcell__ must be a nonlocal cell, not %.200R", - Py_TYPE(cell)); - goto error; +/* store type in class' cell if one is supplied */ +static int +type_new_set_classcell(PyTypeObject *type) +{ + PyObject *cell = _PyDict_GetItemIdWithError(type->tp_dict, + &PyId___classcell__); + if (cell == NULL) { + if (PyErr_Occurred()) { + return -1; } - PyCell_Set(cell, (PyObject *) type); - if (_PyDict_DelItemId(dict, &PyId___classcell__) < 0) { - goto error; + return 0; + } + + /* At least one method requires a reference to its defining class */ + if (!PyCell_Check(cell)) { + PyErr_Format(PyExc_TypeError, + "__classcell__ must be a nonlocal cell, not %.200R", + Py_TYPE(cell)); + return -1; + } + + (void)PyCell_Set(cell, (PyObject *) type); + if (_PyDict_DelItemId(type->tp_dict, &PyId___classcell__) < 0) { + return -1; + } + return 0; +} + + +static int +type_new_set_attrs(const type_new_ctx *ctx, PyTypeObject *type) +{ + if (type_new_set_name(ctx, type) < 0) { + return -1; + } + + if (type_new_set_module(type) < 0) { + return -1; + } + + if (type_new_set_ht_name(type) < 0) { + return -1; + } + + if (type_new_set_doc(type) < 0) { + return -1; + } + + /* Special-case __new__: if it's a plain function, + make it a static function */ + if (type_new_staticmethod(type, &PyId___new__) < 0) { + return -1; + } + + /* Special-case __init_subclass__ and __class_getitem__: + if they are plain functions, make them classmethods */ + if (type_new_classmethod(type, &PyId___init_subclass__) < 0) { + return -1; + } + if (type_new_classmethod(type, &PyId___class_getitem__) < 0) { + return -1; + } + + if (type_new_descriptors(ctx, type) < 0) { + return -1; + } + + type_new_set_slots(ctx, type); + + if (type_new_set_classcell(type) < 0) { + return -1; + } + return 0; +} + + +static int +type_new_get_slots(type_new_ctx *ctx, PyObject *dict) +{ + _Py_IDENTIFIER(__slots__); + PyObject *slots = _PyDict_GetItemIdWithError(dict, &PyId___slots__); + if (slots == NULL) { + if (PyErr_Occurred()) { + return -1; } + ctx->slots = NULL; + ctx->nslot = 0; + return 0; + } + + // Make it into a tuple + PyObject *new_slots; + if (PyUnicode_Check(slots)) { + new_slots = PyTuple_Pack(1, slots); + } + else { + new_slots = PySequence_Tuple(slots); } - else if (PyErr_Occurred()) { + if (new_slots == NULL) { + return -1; + } + assert(PyTuple_CheckExact(new_slots)); + ctx->slots = new_slots; + ctx->nslot = PyTuple_GET_SIZE(new_slots); + return 0; +} + + +static PyTypeObject* +type_new_init(type_new_ctx *ctx) +{ + PyObject *dict = PyDict_Copy(ctx->orig_dict); + if (dict == NULL) { + goto error; + } + + if (type_new_get_slots(ctx, dict) < 0) { + goto error; + } + assert(!PyErr_Occurred()); + + if (type_new_slots(ctx, dict) < 0) { + goto error; + } + + PyTypeObject *type = type_new_alloc(ctx); + if (type == NULL) { + goto error; + } + + type->tp_dict = dict; + + PyHeapTypeObject *et = (PyHeapTypeObject*)type; + et->ht_slots = ctx->slots; + ctx->slots = NULL; + + return type; + +error: + Py_CLEAR(ctx->slots); + Py_XDECREF(dict); + return NULL; +} + + +static PyObject* +type_new_impl(type_new_ctx *ctx) +{ + PyTypeObject *type = type_new_init(ctx); + if (type == NULL) { + return NULL; + } + + if (type_new_set_attrs(ctx, type) < 0) { goto error; } /* Initialize the rest */ - if (PyType_Ready(type) < 0) + if (PyType_Ready(type) < 0) { goto error; + } - /* Put the proper slots in place */ + // Put the proper slots in place fixup_slot_dispatchers(type); if (type->tp_dictoffset) { + PyHeapTypeObject *et = (PyHeapTypeObject*)type; et->ht_cached_keys = _PyDict_NewKeysForClass(); } - if (set_names(type) < 0) + if (type_new_set_names(type) < 0) { goto error; + } - if (init_subclass(type, kwds) < 0) + if (type_new_init_subclass(type, ctx->kwds) < 0) { goto error; + } - Py_DECREF(dict); + assert(_PyType_CheckConsistency(type)); return (PyObject *)type; error: - Py_XDECREF(dict); - Py_XDECREF(bases); - Py_XDECREF(slots); - Py_XDECREF(type); + Py_DECREF(type); return NULL; } -static const short slotoffsets[] = { - -1, /* invalid slot */ + +static int +type_new_get_bases(type_new_ctx *ctx, PyObject **type) +{ + Py_ssize_t nbases = PyTuple_GET_SIZE(ctx->bases); + if (nbases == 0) { + // Adjust for empty tuple bases + ctx->base = &PyBaseObject_Type; + PyObject *new_bases = PyTuple_Pack(1, ctx->base); + if (new_bases == NULL) { + return -1; + } + ctx->bases = new_bases; + return 0; + } + + _Py_IDENTIFIER(__mro_entries__); + for (Py_ssize_t i = 0; i < nbases; i++) { + PyObject *base = PyTuple_GET_ITEM(ctx->bases, i); + if (PyType_Check(base)) { + continue; + } + PyObject *mro_entries; + if (_PyObject_LookupAttrId(base, &PyId___mro_entries__, + &mro_entries) < 0) { + return -1; + } + if (mro_entries != NULL) { + PyErr_SetString(PyExc_TypeError, + "type() doesn't support MRO entry resolution; " + "use types.new_class()"); + Py_DECREF(mro_entries); + return -1; + } + } + + // Search the bases for the proper metatype to deal with this + PyTypeObject *winner; + winner = _PyType_CalculateMetaclass(ctx->metatype, ctx->bases); + if (winner == NULL) { + return -1; + } + + if (winner != ctx->metatype) { + if (winner->tp_new != type_new) { + /* Pass it to the winner */ + *type = winner->tp_new(winner, ctx->args, ctx->kwds); + if (*type == NULL) { + return -1; + } + return 1; + } + + ctx->metatype = winner; + } + + /* Calculate best base, and check that all bases are type objects */ + PyTypeObject *base = best_base(ctx->bases); + if (base == NULL) { + return -1; + } + + ctx->base = base; + ctx->bases = Py_NewRef(ctx->bases); + return 0; +} + + +static PyObject * +type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) +{ + assert(args != NULL && PyTuple_Check(args)); + assert(kwds == NULL || PyDict_Check(kwds)); + + /* Parse arguments: (name, bases, dict) */ + PyObject *name, *bases, *orig_dict; + if (!PyArg_ParseTuple(args, "UO!O!:type.__new__", + &name, + &PyTuple_Type, &bases, + &PyDict_Type, &orig_dict)) + { + return NULL; + } + + type_new_ctx ctx = { + .metatype = metatype, + .args = args, + .kwds = kwds, + .orig_dict = orig_dict, + .name = name, + .bases = bases, + .base = NULL, + .slots = NULL, + .nslot = 0, + .add_dict = 0, + .add_weak = 0, + .may_add_dict = 0, + .may_add_weak = 0}; + PyObject *type = NULL; + int res = type_new_get_bases(&ctx, &type); + if (res < 0) { + assert(PyErr_Occurred()); + return NULL; + } + if (res == 1) { + assert(type != NULL); + return type; + } + assert(ctx.base != NULL); + assert(ctx.bases != NULL); + + type = type_new_impl(&ctx); + Py_DECREF(ctx.bases); + return type; +} + + +static PyObject * +type_vectorcall(PyObject *metatype, PyObject *const *args, + size_t nargsf, PyObject *kwnames) +{ + Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); + if (nargs == 1 && metatype == (PyObject *)&PyType_Type){ + if (!_PyArg_NoKwnames("type", kwnames)) { + return NULL; + } + return Py_NewRef(Py_TYPE(args[0])); + } + /* In other (much less common) cases, fall back to + more flexible calling conventions. */ + PyThreadState *tstate = PyThreadState_GET(); + return _PyObject_MakeTpCall(tstate, metatype, args, nargs, kwnames); +} + +/* An array of type slot offsets corresponding to Py_tp_* constants, + * for use in e.g. PyType_Spec and PyType_GetSlot. + * Each entry has two offsets: "slot_offset" and "subslot_offset". + * If is subslot_offset is -1, slot_offset is an offset within the + * PyTypeObject struct. + * Otherwise slot_offset is an offset to a pointer to a sub-slots struct + * (such as "tp_as_number"), and subslot_offset is the offset within + * that struct. + * The actual table is generated by a script. + */ +static const PySlot_Offset pyslot_offsets[] = { + {0, 0}, #include "typeslots.inc" }; @@ -2893,10 +3372,12 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) PyHeapTypeObject *res; PyObject *modname; PyTypeObject *type, *base; + int r; const PyType_Slot *slot; Py_ssize_t nmembers, weaklistoffset, dictoffset, vectorcalloffset; char *res_start; + short slot_offset, subslot_offset; nmembers = weaklistoffset = dictoffset = vectorcalloffset = 0; for (slot = spec->slots; slot->slot; slot++) { @@ -2982,8 +3463,9 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) } } else if (!PyTuple_Check(bases)) { - PyErr_SetString(PyExc_SystemError, "bases is not a tuple"); - goto fail; + bases = PyTuple_Pack(1, bases); + if (!bases) + goto fail; } else { Py_INCREF(bases); @@ -3019,7 +3501,7 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) for (slot = spec->slots; slot->slot; slot++) { if (slot->slot < 0 - || (size_t)slot->slot >= Py_ARRAY_LENGTH(slotoffsets)) { + || (size_t)slot->slot >= Py_ARRAY_LENGTH(pyslot_offsets)) { PyErr_SetString(PyExc_RuntimeError, "invalid slot offset"); goto fail; } @@ -3030,15 +3512,18 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) else if (slot->slot == Py_tp_doc) { /* For the docstring slot, which usually points to a static string literal, we need to make a copy */ - const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, slot->pfunc); - size_t len = strlen(old_doc)+1; - char *tp_doc = PyObject_MALLOC(len); + if (slot->pfunc == NULL) { + type->tp_doc = NULL; + continue; + } + size_t len = strlen(slot->pfunc)+1; + char *tp_doc = PyObject_Malloc(len); if (tp_doc == NULL) { type->tp_doc = NULL; PyErr_NoMemory(); goto fail; } - memcpy(tp_doc, old_doc, len); + memcpy(tp_doc, slot->pfunc, len); type->tp_doc = tp_doc; } else if (slot->slot == Py_tp_members) { @@ -3049,7 +3534,15 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) } else { /* Copy other slots directly */ - *(void**)(res_start + slotoffsets[slot->slot]) = slot->pfunc; + PySlot_Offset slotoffsets = pyslot_offsets[slot->slot]; + slot_offset = slotoffsets.slot_offset; + if (slotoffsets.subslot_offset == -1) { + *(void**)((char*)res_start + slot_offset) = slot->pfunc; + } else { + void *parent_slot = *(void**)((char*)res_start + slot_offset); + subslot_offset = slotoffsets.subslot_offset; + *(void**)((char*)parent_slot + subslot_offset) = slot->pfunc; + } } } if (type->tp_dealloc == NULL) { @@ -3070,6 +3563,16 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) res->ht_cached_keys = _PyDict_NewKeysForClass(); } + if (type->tp_doc) { + PyObject *__doc__ = PyUnicode_FromString(_PyType_DocWithoutSignature(type->tp_name, type->tp_doc)); + if (!__doc__) + goto fail; + r = _PyDict_SetItemId(type->tp_dict, &PyId___doc__, __doc__); + Py_DECREF(__doc__); + if (r < 0) + goto fail; + } + if (weaklistoffset) { type->tp_weaklistoffset = weaklistoffset; if (PyDict_DelItemString((PyObject *)type->tp_dict, "__weaklistoffset__") < 0) @@ -3082,21 +3585,21 @@ PyType_FromModuleAndSpec(PyObject *module, PyType_Spec *spec, PyObject *bases) } /* Set type.__module__ */ - if (_PyDict_GetItemIdWithError(type->tp_dict, &PyId___module__) == NULL) { - if (PyErr_Occurred()) { - goto fail; - } + r = _PyDict_ContainsId(type->tp_dict, &PyId___module__); + if (r < 0) { + goto fail; + } + if (r == 0) { s = strrchr(spec->name, '.'); if (s != NULL) { - int err; modname = PyUnicode_FromStringAndSize( spec->name, (Py_ssize_t)(s - spec->name)); if (modname == NULL) { goto fail; } - err = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); + r = _PyDict_SetItemId(type->tp_dict, &PyId___module__, modname); Py_DECREF(modname); - if (err != 0) + if (r != 0) goto fail; } else { if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, @@ -3130,15 +3633,23 @@ _PyType_GetQualName(PyTypeObject *type) void * PyType_GetSlot(PyTypeObject *type, int slot) { - if (!_PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE) || slot < 0) { + void *parent_slot; + int slots_len = Py_ARRAY_LENGTH(pyslot_offsets); + + if (slot <= 0 || slot >= slots_len) { PyErr_BadInternalCall(); return NULL; } - if ((size_t)slot >= Py_ARRAY_LENGTH(slotoffsets)) { - /* Extension module requesting slot from a future version */ + + parent_slot = *(void**)((char*)type + pyslot_offsets[slot].slot_offset); + if (parent_slot == NULL) { return NULL; } - return *(void**)(((char*)type) + slotoffsets[slot]); + /* Return slot directly if we have no sub slot. */ + if (pyslot_offsets[slot].subslot_offset == -1) { + return parent_slot; + } + return *(void**)((char*)parent_slot + pyslot_offsets[slot].subslot_offset); } PyObject * @@ -3172,9 +3683,53 @@ PyType_GetModuleState(PyTypeObject *type) if (m == NULL) { return NULL; } - return PyModule_GetState(m); + return _PyModule_GetState(m); +} + + +/* Get the module of the first superclass where the module has the + * given PyModuleDef. + * Implemented by walking the MRO, is relatively slow. + * + * This is internal API for experimentation within stdlib. Discussion: + * https://mail.python.org/archives/list/capi-sig@python.org/thread/T3P2QNLNLBRFHWSKYSTPMVEIL2EEKFJU/ + */ +PyObject * +_PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def) +{ + assert(PyType_Check(type)); + + PyObject *mro = type->tp_mro; + // The type must be ready + assert(mro != NULL); + assert(PyTuple_Check(mro)); + // mro_invoke() ensures that the type MRO cannot be empty, so we don't have + // to check i < PyTuple_GET_SIZE(mro) at the first loop iteration. + assert(PyTuple_GET_SIZE(mro) >= 1); + + Py_ssize_t n = PyTuple_GET_SIZE(mro); + for (Py_ssize_t i = 0; i < n; i++) { + PyObject *super = PyTuple_GET_ITEM(mro, i); + if(!_PyType_HasFeature((PyTypeObject *)super, Py_TPFLAGS_HEAPTYPE)) { + // Static types in the MRO need to be skipped + continue; + } + + PyHeapTypeObject *ht = (PyHeapTypeObject*)super; + PyObject *module = ht->ht_module; + if (module && _PyModule_GetDef(module) == def) { + return module; + } + } + + PyErr_Format( + PyExc_TypeError, + "_PyType_GetModuleByDef: No superclass of '%s' has the given module", + type->tp_name); + return NULL; } + /* Internal API to look for a name through the MRO, bypassing the method cache. This returns a borrowed reference, and might set an exception. 'error' is set to: -1: error with exception; 1: error without exception; 0: ok */ @@ -3245,20 +3800,17 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) PyObject *res; int error; -#ifdef MCACHE - if (MCACHE_CACHEABLE_NAME(name) && - _PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)) { - /* fast path */ - unsigned int h = MCACHE_HASH_METHOD(type, name); - if (method_cache[h].version == type->tp_version_tag && - method_cache[h].name == name) { + unsigned int h = MCACHE_HASH_METHOD(type, name); + struct type_cache *cache = get_type_cache(); + struct type_cache_entry *entry = &cache->hashtable[h]; + if (entry->version == type->tp_version_tag && + entry->name == name) { #if MCACHE_STATS - method_cache_hits++; + cache->hits++; #endif - return method_cache[h].value; - } + assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)); + return entry->value; } -#endif /* We may end up clearing live exceptions below, so make sure it's ours. */ assert(!PyErr_Occurred()); @@ -3280,22 +3832,23 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name) return NULL; } -#ifdef MCACHE - if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(type)) { - unsigned int h = MCACHE_HASH_METHOD(type, name); - method_cache[h].version = type->tp_version_tag; - method_cache[h].value = res; /* borrowed */ - Py_INCREF(name); + if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(cache, type)) { + h = MCACHE_HASH_METHOD(type, name); + struct type_cache_entry *entry = &cache->hashtable[h]; + entry->version = type->tp_version_tag; + entry->value = res; /* borrowed */ assert(((PyASCIIObject *)(name))->hash != -1); #if MCACHE_STATS - if (method_cache[h].name != Py_None && method_cache[h].name != name) - method_cache_collisions++; - else - method_cache_misses++; + if (entry->name != Py_None && entry->name != name) { + cache->collisions++; + } + else { + cache->misses++; + } #endif - Py_SETREF(method_cache[h].name, name); + assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG)); + Py_SETREF(entry->name, Py_NewRef(name)); } -#endif return res; } @@ -3345,7 +3898,7 @@ type_getattro(PyTypeObject *type, PyObject *name) } /* Initialize this type (we'll assume the metatype is initialized) */ - if (type->tp_dict == NULL) { + if (!_PyType_IsReady(type)) { if (PyType_Ready(type) < 0) return NULL; } @@ -3420,11 +3973,11 @@ static int type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) { int res; - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + if (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) { PyErr_Format( PyExc_TypeError, - "can't set attributes of built-in/extension type '%s'", - type->tp_name); + "cannot set %R attribute of immutable type '%s'", + name, type->tp_name); return -1; } if (PyUnicode_Check(name)) { @@ -3762,6 +4315,11 @@ type_is_gc(PyTypeObject *type) return type->tp_flags & Py_TPFLAGS_HEAPTYPE; } + +static PyNumberMethods type_as_number = { + .nb_or = _Py_union_type_or, // Add __or__ function +}; + PyTypeObject PyType_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "type", /* tp_name */ @@ -3773,7 +4331,7 @@ PyTypeObject PyType_Type = { 0, /* tp_setattr */ 0, /* tp_as_async */ (reprfunc)type_repr, /* tp_repr */ - 0, /* tp_as_number */ + &type_as_number, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ @@ -3805,6 +4363,7 @@ PyTypeObject PyType_Type = { type_new, /* tp_new */ PyObject_GC_Del, /* tp_free */ (inquiry)type_is_gc, /* tp_is_gc */ + .tp_vectorcall = type_vectorcall, }; @@ -4189,10 +4748,10 @@ object_set_class(PyObject *self, PyObject *value, void *closure) In theory the proper fix would be to identify which classes rely on this invariant and somehow disallow __class__ assignment only for them, perhaps via some mechanism like a new Py_TPFLAGS_IMMUTABLE flag (a - "blacklisting" approach). But in practice, since this problem wasn't + "denylisting" approach). But in practice, since this problem wasn't noticed late in the 3.5 RC cycle, we're taking the conservative approach and reinstating the same HEAPTYPE->HEAPTYPE check that we used - to have, plus a "whitelist". For now, the whitelist consists only of + to have, plus an "allowlist". For now, the allowlist consists only of ModuleType subtypes, since those are the cases that motivated the patch in the first place -- see https://bugs.python.org/issue22986 -- and since module objects are mutable we can be sure that they are @@ -4207,10 +4766,10 @@ object_set_class(PyObject *self, PyObject *value, void *closure) */ if (!(PyType_IsSubtype(newto, &PyModule_Type) && PyType_IsSubtype(oldto, &PyModule_Type)) && - (!(newto->tp_flags & Py_TPFLAGS_HEAPTYPE) || - !(oldto->tp_flags & Py_TPFLAGS_HEAPTYPE))) { + (_PyType_HasFeature(newto, Py_TPFLAGS_IMMUTABLETYPE) || + _PyType_HasFeature(oldto, Py_TPFLAGS_IMMUTABLETYPE))) { PyErr_Format(PyExc_TypeError, - "__class__ assignment only supported for heap types " + "__class__ assignment only supported for mutable types " "or ModuleType subclasses"); return -1; } @@ -4770,8 +5329,11 @@ object___reduce_ex___impl(PyObject *self, int protocol) _Py_IDENTIFIER(__reduce__); if (objreduce == NULL) { - objreduce = _PyDict_GetItemId(PyBaseObject_Type.tp_dict, - &PyId___reduce__); + objreduce = _PyDict_GetItemIdWithError(PyBaseObject_Type.tp_dict, + &PyId___reduce__); + if (objreduce == NULL && PyErr_Occurred()) { + return NULL; + } } if (_PyObject_LookupAttrId(self, &PyId___reduce__, &reduce) < 0) { @@ -4989,96 +5551,98 @@ PyTypeObject PyBaseObject_Type = { }; -/* Add the methods from tp_methods to the __dict__ in a type object */ - static int -add_methods(PyTypeObject *type, PyMethodDef *meth) +type_add_method(PyTypeObject *type, PyMethodDef *meth) { - PyObject *dict = type->tp_dict; - PyObject *name; - - for (; meth->ml_name != NULL; meth++) { - PyObject *descr; - int err; - int isdescr = 1; - if (meth->ml_flags & METH_CLASS) { - if (meth->ml_flags & METH_STATIC) { - PyErr_SetString(PyExc_ValueError, - "method cannot be both class and static"); - return -1; - } - descr = PyDescr_NewClassMethod(type, meth); - } - else if (meth->ml_flags & METH_STATIC) { - PyObject *cfunc = PyCFunction_NewEx(meth, (PyObject*)type, NULL); - if (cfunc == NULL) - return -1; - descr = PyStaticMethod_New(cfunc); - isdescr = 0; // PyStaticMethod is not PyDescrObject - Py_DECREF(cfunc); - } - else { - descr = PyDescr_NewMethod(type, meth); - } - if (descr == NULL) + PyObject *descr; + int isdescr = 1; + if (meth->ml_flags & METH_CLASS) { + if (meth->ml_flags & METH_STATIC) { + PyErr_SetString(PyExc_ValueError, + "method cannot be both class and static"); return -1; - - if (isdescr) { - name = PyDescr_NAME(descr); } - else { - name = PyUnicode_FromString(meth->ml_name); - if (name == NULL) { - Py_DECREF(descr); - return -1; - } + descr = PyDescr_NewClassMethod(type, meth); + } + else if (meth->ml_flags & METH_STATIC) { + PyObject *cfunc = PyCFunction_NewEx(meth, (PyObject*)type, NULL); + if (cfunc == NULL) { + return -1; } + descr = PyStaticMethod_New(cfunc); + isdescr = 0; // PyStaticMethod is not PyDescrObject + Py_DECREF(cfunc); + } + else { + descr = PyDescr_NewMethod(type, meth); + } + if (descr == NULL) { + return -1; + } - if (!(meth->ml_flags & METH_COEXIST)) { - if (PyDict_GetItemWithError(dict, name)) { - if (!isdescr) { - Py_DECREF(name); - } - Py_DECREF(descr); - continue; - } - else if (PyErr_Occurred()) { - if (!isdescr) { - Py_DECREF(name); - } - return -1; - } - } - err = PyDict_SetItem(dict, name, descr); - if (!isdescr) { - Py_DECREF(name); + PyObject *name; + if (isdescr) { + name = PyDescr_NAME(descr); + } + else { + name = PyUnicode_FromString(meth->ml_name); + if (name == NULL) { + Py_DECREF(descr); + return -1; } - Py_DECREF(descr); - if (err < 0) + } + + int err; + if (!(meth->ml_flags & METH_COEXIST)) { + err = PyDict_SetDefault(type->tp_dict, name, descr) == NULL; + } + else { + err = PyDict_SetItem(type->tp_dict, name, descr) < 0; + } + if (!isdescr) { + Py_DECREF(name); + } + Py_DECREF(descr); + if (err) { + return -1; + } + return 0; +} + + +/* Add the methods from tp_methods to the __dict__ in a type object */ +static int +type_add_methods(PyTypeObject *type) +{ + PyMethodDef *meth = type->tp_methods; + if (meth == NULL) { + return 0; + } + + for (; meth->ml_name != NULL; meth++) { + if (type_add_method(type, meth) < 0) { return -1; + } } return 0; } + static int -add_members(PyTypeObject *type, PyMemberDef *memb) +type_add_members(PyTypeObject *type) { - PyObject *dict = type->tp_dict; + PyMemberDef *memb = type->tp_members; + if (memb == NULL) { + return 0; + } + PyObject *dict = type->tp_dict; for (; memb->name != NULL; memb++) { PyObject *descr = PyDescr_NewMember(type, memb); if (descr == NULL) return -1; - if (PyDict_GetItemWithError(dict, PyDescr_NAME(descr))) { - Py_DECREF(descr); - continue; - } - else if (PyErr_Occurred()) { - Py_DECREF(descr); - return -1; - } - if (PyDict_SetItem(dict, PyDescr_NAME(descr), descr) < 0) { + if (PyDict_SetDefault(dict, PyDescr_NAME(descr), descr) == NULL) { Py_DECREF(descr); return -1; } @@ -5087,25 +5651,23 @@ add_members(PyTypeObject *type, PyMemberDef *memb) return 0; } + static int -add_getset(PyTypeObject *type, PyGetSetDef *gsp) +type_add_getset(PyTypeObject *type) { - PyObject *dict = type->tp_dict; + PyGetSetDef *gsp = type->tp_getset; + if (gsp == NULL) { + return 0; + } + PyObject *dict = type->tp_dict; for (; gsp->name != NULL; gsp++) { PyObject *descr = PyDescr_NewGetSet(type, gsp); - if (descr == NULL) - return -1; - - if (PyDict_GetItemWithError(dict, PyDescr_NAME(descr))) { - Py_DECREF(descr); - continue; - } - else if (PyErr_Occurred()) { - Py_DECREF(descr); + if (descr == NULL) { return -1; } - if (PyDict_SetItem(dict, PyDescr_NAME(descr), descr) < 0) { + + if (PyDict_SetDefault(dict, PyDescr_NAME(descr), descr) == NULL) { Py_DECREF(descr); return -1; } @@ -5114,10 +5676,10 @@ add_getset(PyTypeObject *type, PyGetSetDef *gsp) return 0; } + static void inherit_special(PyTypeObject *type, PyTypeObject *base) { - /* Copying tp_traverse and tp_clear is connected to the GC flags */ if (!(type->tp_flags & Py_TPFLAGS_HAVE_GC) && (base->tp_flags & Py_TPFLAGS_HAVE_GC) && @@ -5128,53 +5690,48 @@ inherit_special(PyTypeObject *type, PyTypeObject *base) if (type->tp_clear == NULL) type->tp_clear = base->tp_clear; } - { - /* The condition below could use some explanation. - It appears that tp_new is not inherited for static types - whose base class is 'object'; this seems to be a precaution - so that old extension types don't suddenly become - callable (object.__new__ wouldn't insure the invariants - that the extension type's own factory function ensures). - Heap types, of course, are under our control, so they do - inherit tp_new; static extension types that specify some - other built-in type as the default also - inherit object.__new__. */ - if (base != &PyBaseObject_Type || - (type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { - if (type->tp_new == NULL) - type->tp_new = base->tp_new; - } - } + if (type->tp_basicsize == 0) type->tp_basicsize = base->tp_basicsize; /* Copy other non-function slots */ -#undef COPYVAL #define COPYVAL(SLOT) \ - if (type->SLOT == 0) type->SLOT = base->SLOT + if (type->SLOT == 0) { type->SLOT = base->SLOT; } COPYVAL(tp_itemsize); COPYVAL(tp_weaklistoffset); COPYVAL(tp_dictoffset); +#undef COPYVAL /* Setup fast subclass flags */ - if (PyType_IsSubtype(base, (PyTypeObject*)PyExc_BaseException)) + if (PyType_IsSubtype(base, (PyTypeObject*)PyExc_BaseException)) { type->tp_flags |= Py_TPFLAGS_BASE_EXC_SUBCLASS; - else if (PyType_IsSubtype(base, &PyType_Type)) + } + else if (PyType_IsSubtype(base, &PyType_Type)) { type->tp_flags |= Py_TPFLAGS_TYPE_SUBCLASS; - else if (PyType_IsSubtype(base, &PyLong_Type)) + } + else if (PyType_IsSubtype(base, &PyLong_Type)) { type->tp_flags |= Py_TPFLAGS_LONG_SUBCLASS; - else if (PyType_IsSubtype(base, &PyBytes_Type)) + } + else if (PyType_IsSubtype(base, &PyBytes_Type)) { type->tp_flags |= Py_TPFLAGS_BYTES_SUBCLASS; - else if (PyType_IsSubtype(base, &PyUnicode_Type)) + } + else if (PyType_IsSubtype(base, &PyUnicode_Type)) { type->tp_flags |= Py_TPFLAGS_UNICODE_SUBCLASS; - else if (PyType_IsSubtype(base, &PyTuple_Type)) + } + else if (PyType_IsSubtype(base, &PyTuple_Type)) { type->tp_flags |= Py_TPFLAGS_TUPLE_SUBCLASS; - else if (PyType_IsSubtype(base, &PyList_Type)) + } + else if (PyType_IsSubtype(base, &PyList_Type)) { type->tp_flags |= Py_TPFLAGS_LIST_SUBCLASS; - else if (PyType_IsSubtype(base, &PyDict_Type)) + } + else if (PyType_IsSubtype(base, &PyDict_Type)) { type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS; + } + if (PyType_HasFeature(base, _Py_TPFLAGS_MATCH_SELF)) { + type->tp_flags |= _Py_TPFLAGS_MATCH_SELF; + } } static int @@ -5184,14 +5741,14 @@ overrides_hash(PyTypeObject *type) _Py_IDENTIFIER(__eq__); assert(dict != NULL); - if (_PyDict_GetItemId(dict, &PyId___eq__) != NULL) - return 1; - if (_PyDict_GetItemId(dict, &PyId___hash__) != NULL) - return 1; - return 0; + int r = _PyDict_ContainsId(dict, &PyId___eq__); + if (r == 0) { + r = _PyDict_ContainsId(dict, &PyId___hash__); + } + return r; } -static void +static int inherit_slots(PyTypeObject *type, PyTypeObject *base) { PyTypeObject *basebase; @@ -5334,11 +5891,16 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) /* Copy comparison-related slots only when not overriding them anywhere */ if (type->tp_richcompare == NULL && - type->tp_hash == NULL && - !overrides_hash(type)) + type->tp_hash == NULL) { - type->tp_richcompare = base->tp_richcompare; - type->tp_hash = base->tp_hash; + int r = overrides_hash(type); + if (r < 0) { + return -1; + } + if (!r) { + type->tp_richcompare = base->tp_richcompare; + type->tp_hash = base->tp_hash; + } } } { @@ -5381,24 +5943,17 @@ inherit_slots(PyTypeObject *type, PyTypeObject *base) * obvious to be done -- the type is on its own. */ } + return 0; } static int add_operators(PyTypeObject *); +static int add_tp_new_wrapper(PyTypeObject *type); -int -PyType_Ready(PyTypeObject *type) -{ - PyObject *dict, *bases; - PyTypeObject *base; - Py_ssize_t i, n; - - if (type->tp_flags & Py_TPFLAGS_READY) { - assert(_PyType_CheckConsistency(type)); - return 0; - } - _PyObject_ASSERT((PyObject *)type, - (type->tp_flags & Py_TPFLAGS_READYING) == 0); +#define COLLECTION_FLAGS (Py_TPFLAGS_SEQUENCE | Py_TPFLAGS_MAPPING) +static int +type_ready_checks(PyTypeObject *type) +{ /* Consistency checks for PEP 590: * - Py_TPFLAGS_METHOD_DESCRIPTOR requires tp_descr_get * - Py_TPFLAGS_HAVE_VECTORCALL requires tp_call and @@ -5413,38 +5968,43 @@ PyType_Ready(PyTypeObject *type) _PyObject_ASSERT((PyObject *)type, type->tp_call != NULL); } - type->tp_flags |= Py_TPFLAGS_READYING; - -#ifdef Py_TRACE_REFS - /* PyType_Ready is the closest thing we have to a choke point - * for type objects, so is the best place I can think of to try - * to get type objects into the doubly-linked list of all objects. - * Still, not all type objects go through PyType_Ready. - */ - _Py_AddToAllObjects((PyObject *)type, 0); -#endif + /* Consistency checks for pattern matching + * Py_TPFLAGS_SEQUENCE and Py_TPFLAGS_MAPPING are mutually exclusive */ + _PyObject_ASSERT((PyObject *)type, (type->tp_flags & COLLECTION_FLAGS) != COLLECTION_FLAGS); if (type->tp_name == NULL) { PyErr_Format(PyExc_SystemError, "Type does not define the tp_name field."); - goto error; + return -1; } + return 0; +} + +static int +type_ready_set_bases(PyTypeObject *type) +{ /* Initialize tp_base (defaults to BaseObject unless that's us) */ - base = type->tp_base; + PyTypeObject *base = type->tp_base; if (base == NULL && type != &PyBaseObject_Type) { - base = type->tp_base = &PyBaseObject_Type; - Py_INCREF(base); + base = &PyBaseObject_Type; + if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) { + type->tp_base = (PyTypeObject*)Py_NewRef((PyObject*)base); + } + else { + type->tp_base = base; + } } + assert(type->tp_base != NULL || type == &PyBaseObject_Type); /* Now the only way base can still be NULL is if type is - * &PyBaseObject_Type. - */ + * &PyBaseObject_Type. */ /* Initialize the base class */ - if (base != NULL && base->tp_dict == NULL) { - if (PyType_Ready(base) < 0) - goto error; + if (base != NULL && !_PyType_IsReady(base)) { + if (PyType_Ready(base) < 0) { + return -1; + } } /* Initialize ob_type if NULL. This means extensions that want to be @@ -5459,78 +6019,190 @@ PyType_Ready(PyTypeObject *type) } /* Initialize tp_bases */ - bases = type->tp_bases; + PyObject *bases = type->tp_bases; if (bases == NULL) { - if (base == NULL) + PyTypeObject *base = type->tp_base; + if (base == NULL) { bases = PyTuple_New(0); - else + } + else { bases = PyTuple_Pack(1, base); - if (bases == NULL) - goto error; + } + if (bases == NULL) { + return -1; + } type->tp_bases = bases; } + return 0; +} + + +static int +type_ready_set_dict(PyTypeObject *type) +{ + if (type->tp_dict != NULL) { + return 0; + } - /* Initialize tp_dict */ - dict = type->tp_dict; + PyObject *dict = PyDict_New(); if (dict == NULL) { - dict = PyDict_New(); - if (dict == NULL) - goto error; - type->tp_dict = dict; + return -1; } + type->tp_dict = dict; + return 0; +} - /* Add type-specific descriptors to tp_dict */ - if (add_operators(type) < 0) - goto error; - if (type->tp_methods != NULL) { - if (add_methods(type, type->tp_methods) < 0) - goto error; + +/* If the type dictionary doesn't contain a __doc__, set it from + the tp_doc slot. */ +static int +type_dict_set_doc(PyTypeObject *type) +{ + int r = _PyDict_ContainsId(type->tp_dict, &PyId___doc__); + if (r < 0) { + return -1; } - if (type->tp_members != NULL) { - if (add_members(type, type->tp_members) < 0) - goto error; + if (r > 0) { + return 0; } - if (type->tp_getset != NULL) { - if (add_getset(type, type->tp_getset) < 0) - goto error; + + if (type->tp_doc != NULL) { + const char *doc_str; + doc_str = _PyType_DocWithoutSignature(type->tp_name, type->tp_doc); + PyObject *doc = PyUnicode_FromString(doc_str); + if (doc == NULL) { + return -1; + } + + if (_PyDict_SetItemId(type->tp_dict, &PyId___doc__, doc) < 0) { + Py_DECREF(doc); + return -1; + } + Py_DECREF(doc); } + else { + if (_PyDict_SetItemId(type->tp_dict, &PyId___doc__, Py_None) < 0) { + return -1; + } + } + return 0; +} - /* Calculate method resolution order */ - if (mro_internal(type, NULL) < 0) - goto error; - /* Inherit special flags from dominant base */ - if (type->tp_base != NULL) - inherit_special(type, type->tp_base); +static int +type_ready_fill_dict(PyTypeObject *type) +{ + /* Add type-specific descriptors to tp_dict */ + if (add_operators(type) < 0) { + return -1; + } + if (type_add_methods(type) < 0) { + return -1; + } + if (type_add_members(type) < 0) { + return -1; + } + if (type_add_getset(type) < 0) { + return -1; + } + if (type_dict_set_doc(type) < 0) { + return -1; + } + return 0; +} - /* Initialize tp_dict properly */ - bases = type->tp_mro; - assert(bases != NULL); - assert(PyTuple_Check(bases)); - n = PyTuple_GET_SIZE(bases); - for (i = 1; i < n; i++) { - PyObject *b = PyTuple_GET_ITEM(bases, i); - if (PyType_Check(b)) - inherit_slots(type, (PyTypeObject *)b); + +static int +type_ready_mro(PyTypeObject *type) +{ + /* Calculate method resolution order */ + if (mro_internal(type, NULL) < 0) { + return -1; } + assert(type->tp_mro != NULL); + assert(PyTuple_Check(type->tp_mro)); /* All bases of statically allocated type should be statically allocated */ - if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) - for (i = 0; i < n; i++) { - PyObject *b = PyTuple_GET_ITEM(bases, i); - if (PyType_Check(b) && - (((PyTypeObject *)b)->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + PyObject *mro = type->tp_mro; + Py_ssize_t n = PyTuple_GET_SIZE(mro); + for (Py_ssize_t i = 0; i < n; i++) { + PyTypeObject *base = (PyTypeObject *)PyTuple_GET_ITEM(mro, i); + if (PyType_Check(base) && (base->tp_flags & Py_TPFLAGS_HEAPTYPE)) { PyErr_Format(PyExc_TypeError, "type '%.100s' is not dynamically allocated but " "its base type '%.100s' is dynamically allocated", - type->tp_name, ((PyTypeObject *)b)->tp_name); - goto error; + type->tp_name, base->tp_name); + return -1; } } + } + return 0; +} + + +// For static types, inherit tp_as_xxx structures from the base class +// if it's NULL. +// +// For heap types, tp_as_xxx structures are not NULL: they are set to the +// PyHeapTypeObject.as_xxx fields by type_new_alloc(). +static void +type_ready_inherit_as_structs(PyTypeObject *type, PyTypeObject *base) +{ + if (type->tp_as_async == NULL) { + type->tp_as_async = base->tp_as_async; + } + if (type->tp_as_number == NULL) { + type->tp_as_number = base->tp_as_number; + } + if (type->tp_as_sequence == NULL) { + type->tp_as_sequence = base->tp_as_sequence; + } + if (type->tp_as_mapping == NULL) { + type->tp_as_mapping = base->tp_as_mapping; + } + if (type->tp_as_buffer == NULL) { + type->tp_as_buffer = base->tp_as_buffer; + } +} + +static void +inherit_patma_flags(PyTypeObject *type, PyTypeObject *base) { + if ((type->tp_flags & COLLECTION_FLAGS) == 0) { + type->tp_flags |= base->tp_flags & COLLECTION_FLAGS; + } +} + +static int +type_ready_inherit(PyTypeObject *type) +{ + /* Inherit special flags from dominant base */ + PyTypeObject *base = type->tp_base; + if (base != NULL) { + inherit_special(type, base); + } + + // Inherit slots + PyObject *mro = type->tp_mro; + Py_ssize_t n = PyTuple_GET_SIZE(type->tp_mro); + for (Py_ssize_t i = 1; i < n; i++) { + PyObject *b = PyTuple_GET_ITEM(mro, i); + if (PyType_Check(b)) { + if (inherit_slots(type, (PyTypeObject *)b) < 0) { + return -1; + } + inherit_patma_flags(type, (PyTypeObject *)b); + } + } + + if (base != NULL) { + type_ready_inherit_as_structs(type, base); + } /* Sanity check for tp_free. */ if (_PyType_IS_GC(type) && (type->tp_flags & Py_TPFLAGS_BASETYPE) && - (type->tp_free == NULL || type->tp_free == PyObject_Del)) { + (type->tp_free == NULL || type->tp_free == PyObject_Del)) + { /* This base class needs to call tp_free, but doesn't have * one, or its tp_free is for non-gc'ed objects. */ @@ -5538,87 +6210,175 @@ PyType_Ready(PyTypeObject *type) "gc and is a base type but has inappropriate " "tp_free slot", type->tp_name); - goto error; + return -1; } - /* if the type dictionary doesn't contain a __doc__, set it from - the tp_doc slot. - */ - if (_PyDict_GetItemIdWithError(type->tp_dict, &PyId___doc__) == NULL) { - if (PyErr_Occurred()) { - goto error; + return 0; +} + + +/* Hack for tp_hash and __hash__. + If after all that, tp_hash is still NULL, and __hash__ is not in + tp_dict, set tp_hash to PyObject_HashNotImplemented and + tp_dict['__hash__'] equal to None. + This signals that __hash__ is not inherited. */ +static int +type_ready_set_hash(PyTypeObject *type) +{ + if (type->tp_hash != NULL) { + return 0; + } + + int r = _PyDict_ContainsId(type->tp_dict, &PyId___hash__); + if (r < 0) { + return -1; + } + if (r > 0) { + return 0; + } + + if (_PyDict_SetItemId(type->tp_dict, &PyId___hash__, Py_None) < 0) { + return -1; + } + type->tp_hash = PyObject_HashNotImplemented; + return 0; +} + + +/* Link into each base class's list of subclasses */ +static int +type_ready_add_subclasses(PyTypeObject *type) +{ + PyObject *bases = type->tp_bases; + Py_ssize_t nbase = PyTuple_GET_SIZE(bases); + for (Py_ssize_t i = 0; i < nbase; i++) { + PyObject *b = PyTuple_GET_ITEM(bases, i); + if (PyType_Check(b) && add_subclass((PyTypeObject *)b, type) < 0) { + return -1; } - if (type->tp_doc != NULL) { - const char *old_doc = _PyType_DocWithoutSignature(type->tp_name, - type->tp_doc); - PyObject *doc = PyUnicode_FromString(old_doc); - if (doc == NULL) - goto error; - if (_PyDict_SetItemId(type->tp_dict, &PyId___doc__, doc) < 0) { - Py_DECREF(doc); - goto error; + } + return 0; +} + + +// Set tp_new and the "__new__" key in the type dictionary. +// Use the Py_TPFLAGS_DISALLOW_INSTANTIATION flag. +static int +type_ready_set_new(PyTypeObject *type) +{ + PyTypeObject *base = type->tp_base; + /* The condition below could use some explanation. + + It appears that tp_new is not inherited for static types whose base + class is 'object'; this seems to be a precaution so that old extension + types don't suddenly become callable (object.__new__ wouldn't insure the + invariants that the extension type's own factory function ensures). + + Heap types, of course, are under our control, so they do inherit tp_new; + static extension types that specify some other built-in type as the + default also inherit object.__new__. */ + if (type->tp_new == NULL + && base == &PyBaseObject_Type + && !(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) + { + type->tp_flags |= Py_TPFLAGS_DISALLOW_INSTANTIATION; + } + + if (!(type->tp_flags & Py_TPFLAGS_DISALLOW_INSTANTIATION)) { + if (type->tp_new != NULL) { + // If "__new__" key does not exists in the type dictionary, + // set it to tp_new_wrapper(). + if (add_tp_new_wrapper(type) < 0) { + return -1; } - Py_DECREF(doc); - } else { - if (_PyDict_SetItemId(type->tp_dict, - &PyId___doc__, Py_None) < 0) - goto error; + } + else { + // tp_new is NULL: inherit tp_new from base + type->tp_new = base->tp_new; } } + else { + // Py_TPFLAGS_DISALLOW_INSTANTIATION sets tp_new to NULL + type->tp_new = NULL; + } + return 0; +} + - /* Hack for tp_hash and __hash__. - If after all that, tp_hash is still NULL, and __hash__ is not in - tp_dict, set tp_hash to PyObject_HashNotImplemented and - tp_dict['__hash__'] equal to None. - This signals that __hash__ is not inherited. +static int +type_ready(PyTypeObject *type) +{ + if (type_ready_checks(type) < 0) { + return -1; + } + +#ifdef Py_TRACE_REFS + /* PyType_Ready is the closest thing we have to a choke point + * for type objects, so is the best place I can think of to try + * to get type objects into the doubly-linked list of all objects. + * Still, not all type objects go through PyType_Ready. */ - if (type->tp_hash == NULL) { - if (_PyDict_GetItemIdWithError(type->tp_dict, &PyId___hash__) == NULL) { - if (PyErr_Occurred() || - _PyDict_SetItemId(type->tp_dict, &PyId___hash__, Py_None) < 0) - { - goto error; - } - type->tp_hash = PyObject_HashNotImplemented; - } + _Py_AddToAllObjects((PyObject *)type, 0); +#endif + + /* Initialize tp_dict: _PyType_IsReady() tests if tp_dict != NULL */ + if (type_ready_set_dict(type) < 0) { + return -1; + } + if (type_ready_set_bases(type) < 0) { + return -1; + } + if (type_ready_mro(type) < 0) { + return -1; + } + if (type_ready_set_new(type) < 0) { + return -1; } + if (type_ready_fill_dict(type) < 0) { + return -1; + } + if (type_ready_inherit(type) < 0) { + return -1; + } + if (type_ready_set_hash(type) < 0) { + return -1; + } + if (type_ready_add_subclasses(type) < 0) { + return -1; + } + return 0; +} - /* Some more special stuff */ - base = type->tp_base; - if (base != NULL) { - if (type->tp_as_async == NULL) - type->tp_as_async = base->tp_as_async; - if (type->tp_as_number == NULL) - type->tp_as_number = base->tp_as_number; - if (type->tp_as_sequence == NULL) - type->tp_as_sequence = base->tp_as_sequence; - if (type->tp_as_mapping == NULL) - type->tp_as_mapping = base->tp_as_mapping; - if (type->tp_as_buffer == NULL) - type->tp_as_buffer = base->tp_as_buffer; - } - - /* Link into each base class's list of subclasses */ - bases = type->tp_bases; - n = PyTuple_GET_SIZE(bases); - for (i = 0; i < n; i++) { - PyObject *b = PyTuple_GET_ITEM(bases, i); - if (PyType_Check(b) && - add_subclass((PyTypeObject *)b, type) < 0) - goto error; + +int +PyType_Ready(PyTypeObject *type) +{ + if (type->tp_flags & Py_TPFLAGS_READY) { + assert(_PyType_CheckConsistency(type)); + return 0; + } + _PyObject_ASSERT((PyObject *)type, + (type->tp_flags & Py_TPFLAGS_READYING) == 0); + + type->tp_flags |= Py_TPFLAGS_READYING; + + /* Historically, all static types were immutable. See bpo-43908 */ + if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { + type->tp_flags |= Py_TPFLAGS_IMMUTABLETYPE; + } + + if (type_ready(type) < 0) { + type->tp_flags &= ~Py_TPFLAGS_READYING; + return -1; } /* All done -- set the ready flag */ - type->tp_flags = - (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY; + type->tp_flags = (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY; assert(_PyType_CheckConsistency(type)); return 0; - - error: - type->tp_flags &= ~Py_TPFLAGS_READYING; - return -1; } + static int add_subclass(PyTypeObject *base, PyTypeObject *type) { @@ -6202,8 +6962,8 @@ tp_new_wrapper(PyObject *self, PyObject *args, PyObject *kwds) "__new__() called with non-type 'self'"); return NULL; } - type = (PyTypeObject *)self; + if (!PyTuple_Check(args) || PyTuple_GET_SIZE(args) < 1) { PyErr_Format(PyExc_TypeError, "%s.__new__(): not enough arguments", @@ -6265,21 +7025,21 @@ static struct PyMethodDef tp_new_methoddef[] = { static int add_tp_new_wrapper(PyTypeObject *type) { - PyObject *func; - - if (_PyDict_GetItemIdWithError(type->tp_dict, &PyId___new__) != NULL) + int r = _PyDict_ContainsId(type->tp_dict, &PyId___new__); + if (r > 0) { return 0; - if (PyErr_Occurred()) - return -1; - func = PyCFunction_NewEx(tp_new_methoddef, (PyObject *)type, NULL); - if (func == NULL) + } + if (r < 0) { return -1; - if (_PyDict_SetItemId(type->tp_dict, &PyId___new__, func)) { - Py_DECREF(func); + } + + PyObject *func = PyCFunction_NewEx(tp_new_methoddef, (PyObject *)type, NULL); + if (func == NULL) { return -1; } + r = _PyDict_SetItemId(type->tp_dict, &PyId___new__, func); Py_DECREF(func); - return 0; + return r; } /* Slot wrappers that call the corresponding __foo__ slot. See comments @@ -6394,7 +7154,7 @@ slot_sq_length(PyObject *self) if (res == NULL) return -1; - Py_SETREF(res, PyNumber_Index(res)); + Py_SETREF(res, _PyNumber_Index(res)); if (res == NULL) return -1; @@ -7636,8 +8396,17 @@ update_slot(PyTypeObject *type, PyObject *name) assert(slotdefs_initialized); pp = ptrs; for (p = slotdefs; p->name; p++) { - if (p->name_strobj == name) + assert(PyUnicode_CheckExact(p->name_strobj)); + assert(PyUnicode_CheckExact(name)); +#ifdef INTERN_NAME_STRINGS + if (p->name_strobj == name) { *pp++ = p; + } +#else + if (p->name_strobj == name || _PyUnicode_EQ(p->name_strobj, name)) { + *pp++ = p; + } +#endif } *pp = NULL; for (pp = ptrs; *pp; pp++) { @@ -7659,11 +8428,11 @@ update_slot(PyTypeObject *type, PyObject *name) static void fixup_slot_dispatchers(PyTypeObject *type) { - slotdef *p; - + assert(!PyErr_Occurred()); assert(slotdefs_initialized); - for (p = slotdefs; p->name; ) + for (slotdef *p = slotdefs; p->name; ) { p = update_one_slot(type, p); + } } static void @@ -7681,63 +8450,67 @@ update_all_slots(PyTypeObject* type) } } -/* Call __set_name__ on all descriptors in a newly generated type */ + +/* Call __set_name__ on all attributes (including descriptors) + in a newly generated type */ static int -set_names(PyTypeObject *type) +type_new_set_names(PyTypeObject *type) { - PyObject *names_to_set, *key, *value, *set_name, *tmp; - Py_ssize_t i = 0; - - names_to_set = PyDict_Copy(type->tp_dict); - if (names_to_set == NULL) + PyObject *names_to_set = PyDict_Copy(type->tp_dict); + if (names_to_set == NULL) { return -1; + } + Py_ssize_t i = 0; + PyObject *key, *value; while (PyDict_Next(names_to_set, &i, &key, &value)) { - set_name = _PyObject_LookupSpecial(value, &PyId___set_name__); - if (set_name != NULL) { - tmp = PyObject_CallFunctionObjArgs(set_name, type, key, NULL); - Py_DECREF(set_name); - if (tmp == NULL) { - _PyErr_FormatFromCause(PyExc_RuntimeError, - "Error calling __set_name__ on '%.100s' instance %R " - "in '%.100s'", - Py_TYPE(value)->tp_name, key, type->tp_name); - Py_DECREF(names_to_set); - return -1; + PyObject *set_name = _PyObject_LookupSpecial(value, &PyId___set_name__); + if (set_name == NULL) { + if (PyErr_Occurred()) { + goto error; } - else - Py_DECREF(tmp); + continue; } - else if (PyErr_Occurred()) { - Py_DECREF(names_to_set); - return -1; + + PyObject *res = PyObject_CallFunctionObjArgs(set_name, type, key, NULL); + Py_DECREF(set_name); + + if (res == NULL) { + _PyErr_FormatFromCause(PyExc_RuntimeError, + "Error calling __set_name__ on '%.100s' instance %R " + "in '%.100s'", + Py_TYPE(value)->tp_name, key, type->tp_name); + goto error; } + Py_DECREF(res); } Py_DECREF(names_to_set); return 0; + +error: + Py_DECREF(names_to_set); + return -1; } + /* Call __init_subclass__ on the parent of a newly generated type */ static int -init_subclass(PyTypeObject *type, PyObject *kwds) +type_new_init_subclass(PyTypeObject *type, PyObject *kwds) { - PyObject *super, *func, *result; PyObject *args[2] = {(PyObject *)type, (PyObject *)type}; - - super = _PyObject_FastCall((PyObject *)&PySuper_Type, args, 2); + PyObject *super = _PyObject_FastCall((PyObject *)&PySuper_Type, args, 2); if (super == NULL) { return -1; } - func = _PyObject_GetAttrId(super, &PyId___init_subclass__); + PyObject *func = _PyObject_GetAttrId(super, &PyId___init_subclass__); Py_DECREF(super); if (func == NULL) { return -1; } - - result = PyObject_VectorcallDict(func, NULL, 0, kwds); + PyObject *result = PyObject_VectorcallDict(func, NULL, 0, kwds); Py_DECREF(func); if (result == NULL) { return -1; @@ -7747,6 +8520,7 @@ init_subclass(PyTypeObject *type, PyObject *kwds) return 0; } + /* recurse_down_subclasses() and update_subclasses() are mutually recursive functions to call a callback for all subclasses, but refraining from recursing into subclasses that define 'name'. */ @@ -7783,10 +8557,11 @@ recurse_down_subclasses(PyTypeObject *type, PyObject *name, /* Avoid recursing down into unaffected classes */ dict = subclass->tp_dict; if (dict != NULL && PyDict_Check(dict)) { - if (PyDict_GetItemWithError(dict, name) != NULL) { + int r = PyDict_Contains(dict, name); + if (r > 0) { continue; } - if (PyErr_Occurred()) { + if (r < 0) { return -1; } } @@ -7841,9 +8616,10 @@ add_operators(PyTypeObject *type) ptr = slotptr(type, p->offset); if (!ptr || !*ptr) continue; - if (PyDict_GetItemWithError(dict, p->name_strobj)) + int r = PyDict_Contains(dict, p->name_strobj); + if (r > 0) continue; - if (PyErr_Occurred()) { + if (r < 0) { return -1; } if (*ptr == (void *)PyObject_HashNotImplemented) { @@ -7864,10 +8640,6 @@ add_operators(PyTypeObject *type) Py_DECREF(descr); } } - if (type->tp_new != NULL) { - if (add_tp_new_wrapper(type) < 0) - return -1; - } return 0; } diff --git a/contrib/tools/python3/src/Objects/typeslots.inc b/contrib/tools/python3/src/Objects/typeslots.inc index ffc9bb2e1c..896daa7d80 100644 --- a/contrib/tools/python3/src/Objects/typeslots.inc +++ b/contrib/tools/python3/src/Objects/typeslots.inc @@ -1,81 +1,82 @@ /* Generated by typeslots.py */ -offsetof(PyHeapTypeObject, as_buffer.bf_getbuffer), -offsetof(PyHeapTypeObject, as_buffer.bf_releasebuffer), -offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript), -offsetof(PyHeapTypeObject, as_mapping.mp_length), -offsetof(PyHeapTypeObject, as_mapping.mp_subscript), -offsetof(PyHeapTypeObject, as_number.nb_absolute), -offsetof(PyHeapTypeObject, as_number.nb_add), -offsetof(PyHeapTypeObject, as_number.nb_and), -offsetof(PyHeapTypeObject, as_number.nb_bool), -offsetof(PyHeapTypeObject, as_number.nb_divmod), -offsetof(PyHeapTypeObject, as_number.nb_float), -offsetof(PyHeapTypeObject, as_number.nb_floor_divide), -offsetof(PyHeapTypeObject, as_number.nb_index), -offsetof(PyHeapTypeObject, as_number.nb_inplace_add), -offsetof(PyHeapTypeObject, as_number.nb_inplace_and), -offsetof(PyHeapTypeObject, as_number.nb_inplace_floor_divide), -offsetof(PyHeapTypeObject, as_number.nb_inplace_lshift), -offsetof(PyHeapTypeObject, as_number.nb_inplace_multiply), -offsetof(PyHeapTypeObject, as_number.nb_inplace_or), -offsetof(PyHeapTypeObject, as_number.nb_inplace_power), -offsetof(PyHeapTypeObject, as_number.nb_inplace_remainder), -offsetof(PyHeapTypeObject, as_number.nb_inplace_rshift), -offsetof(PyHeapTypeObject, as_number.nb_inplace_subtract), -offsetof(PyHeapTypeObject, as_number.nb_inplace_true_divide), -offsetof(PyHeapTypeObject, as_number.nb_inplace_xor), -offsetof(PyHeapTypeObject, as_number.nb_int), -offsetof(PyHeapTypeObject, as_number.nb_invert), -offsetof(PyHeapTypeObject, as_number.nb_lshift), -offsetof(PyHeapTypeObject, as_number.nb_multiply), -offsetof(PyHeapTypeObject, as_number.nb_negative), -offsetof(PyHeapTypeObject, as_number.nb_or), -offsetof(PyHeapTypeObject, as_number.nb_positive), -offsetof(PyHeapTypeObject, as_number.nb_power), -offsetof(PyHeapTypeObject, as_number.nb_remainder), -offsetof(PyHeapTypeObject, as_number.nb_rshift), -offsetof(PyHeapTypeObject, as_number.nb_subtract), -offsetof(PyHeapTypeObject, as_number.nb_true_divide), -offsetof(PyHeapTypeObject, as_number.nb_xor), -offsetof(PyHeapTypeObject, as_sequence.sq_ass_item), -offsetof(PyHeapTypeObject, as_sequence.sq_concat), -offsetof(PyHeapTypeObject, as_sequence.sq_contains), -offsetof(PyHeapTypeObject, as_sequence.sq_inplace_concat), -offsetof(PyHeapTypeObject, as_sequence.sq_inplace_repeat), -offsetof(PyHeapTypeObject, as_sequence.sq_item), -offsetof(PyHeapTypeObject, as_sequence.sq_length), -offsetof(PyHeapTypeObject, as_sequence.sq_repeat), -offsetof(PyHeapTypeObject, ht_type.tp_alloc), -offsetof(PyHeapTypeObject, ht_type.tp_base), -offsetof(PyHeapTypeObject, ht_type.tp_bases), -offsetof(PyHeapTypeObject, ht_type.tp_call), -offsetof(PyHeapTypeObject, ht_type.tp_clear), -offsetof(PyHeapTypeObject, ht_type.tp_dealloc), -offsetof(PyHeapTypeObject, ht_type.tp_del), -offsetof(PyHeapTypeObject, ht_type.tp_descr_get), -offsetof(PyHeapTypeObject, ht_type.tp_descr_set), -offsetof(PyHeapTypeObject, ht_type.tp_doc), -offsetof(PyHeapTypeObject, ht_type.tp_getattr), -offsetof(PyHeapTypeObject, ht_type.tp_getattro), -offsetof(PyHeapTypeObject, ht_type.tp_hash), -offsetof(PyHeapTypeObject, ht_type.tp_init), -offsetof(PyHeapTypeObject, ht_type.tp_is_gc), -offsetof(PyHeapTypeObject, ht_type.tp_iter), -offsetof(PyHeapTypeObject, ht_type.tp_iternext), -offsetof(PyHeapTypeObject, ht_type.tp_methods), -offsetof(PyHeapTypeObject, ht_type.tp_new), -offsetof(PyHeapTypeObject, ht_type.tp_repr), -offsetof(PyHeapTypeObject, ht_type.tp_richcompare), -offsetof(PyHeapTypeObject, ht_type.tp_setattr), -offsetof(PyHeapTypeObject, ht_type.tp_setattro), -offsetof(PyHeapTypeObject, ht_type.tp_str), -offsetof(PyHeapTypeObject, ht_type.tp_traverse), -offsetof(PyHeapTypeObject, ht_type.tp_members), -offsetof(PyHeapTypeObject, ht_type.tp_getset), -offsetof(PyHeapTypeObject, ht_type.tp_free), -offsetof(PyHeapTypeObject, as_number.nb_matrix_multiply), -offsetof(PyHeapTypeObject, as_number.nb_inplace_matrix_multiply), -offsetof(PyHeapTypeObject, as_async.am_await), -offsetof(PyHeapTypeObject, as_async.am_aiter), -offsetof(PyHeapTypeObject, as_async.am_anext), -offsetof(PyHeapTypeObject, ht_type.tp_finalize), +{offsetof(PyBufferProcs, bf_getbuffer), offsetof(PyTypeObject, tp_as_buffer)}, +{offsetof(PyBufferProcs, bf_releasebuffer), offsetof(PyTypeObject, tp_as_buffer)}, +{offsetof(PyMappingMethods, mp_ass_subscript), offsetof(PyTypeObject, tp_as_mapping)}, +{offsetof(PyMappingMethods, mp_length), offsetof(PyTypeObject, tp_as_mapping)}, +{offsetof(PyMappingMethods, mp_subscript), offsetof(PyTypeObject, tp_as_mapping)}, +{offsetof(PyNumberMethods, nb_absolute), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_add), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_and), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_bool), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_divmod), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_float), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_floor_divide), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_index), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_add), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_and), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_floor_divide), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_lshift), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_multiply), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_or), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_power), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_remainder), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_rshift), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_subtract), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_true_divide), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_xor), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_int), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_invert), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_lshift), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_multiply), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_negative), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_or), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_positive), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_power), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_remainder), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_rshift), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_subtract), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_true_divide), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_xor), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PySequenceMethods, sq_ass_item), offsetof(PyTypeObject, tp_as_sequence)}, +{offsetof(PySequenceMethods, sq_concat), offsetof(PyTypeObject, tp_as_sequence)}, +{offsetof(PySequenceMethods, sq_contains), offsetof(PyTypeObject, tp_as_sequence)}, +{offsetof(PySequenceMethods, sq_inplace_concat), offsetof(PyTypeObject, tp_as_sequence)}, +{offsetof(PySequenceMethods, sq_inplace_repeat), offsetof(PyTypeObject, tp_as_sequence)}, +{offsetof(PySequenceMethods, sq_item), offsetof(PyTypeObject, tp_as_sequence)}, +{offsetof(PySequenceMethods, sq_length), offsetof(PyTypeObject, tp_as_sequence)}, +{offsetof(PySequenceMethods, sq_repeat), offsetof(PyTypeObject, tp_as_sequence)}, +{-1, offsetof(PyTypeObject, tp_alloc)}, +{-1, offsetof(PyTypeObject, tp_base)}, +{-1, offsetof(PyTypeObject, tp_bases)}, +{-1, offsetof(PyTypeObject, tp_call)}, +{-1, offsetof(PyTypeObject, tp_clear)}, +{-1, offsetof(PyTypeObject, tp_dealloc)}, +{-1, offsetof(PyTypeObject, tp_del)}, +{-1, offsetof(PyTypeObject, tp_descr_get)}, +{-1, offsetof(PyTypeObject, tp_descr_set)}, +{-1, offsetof(PyTypeObject, tp_doc)}, +{-1, offsetof(PyTypeObject, tp_getattr)}, +{-1, offsetof(PyTypeObject, tp_getattro)}, +{-1, offsetof(PyTypeObject, tp_hash)}, +{-1, offsetof(PyTypeObject, tp_init)}, +{-1, offsetof(PyTypeObject, tp_is_gc)}, +{-1, offsetof(PyTypeObject, tp_iter)}, +{-1, offsetof(PyTypeObject, tp_iternext)}, +{-1, offsetof(PyTypeObject, tp_methods)}, +{-1, offsetof(PyTypeObject, tp_new)}, +{-1, offsetof(PyTypeObject, tp_repr)}, +{-1, offsetof(PyTypeObject, tp_richcompare)}, +{-1, offsetof(PyTypeObject, tp_setattr)}, +{-1, offsetof(PyTypeObject, tp_setattro)}, +{-1, offsetof(PyTypeObject, tp_str)}, +{-1, offsetof(PyTypeObject, tp_traverse)}, +{-1, offsetof(PyTypeObject, tp_members)}, +{-1, offsetof(PyTypeObject, tp_getset)}, +{-1, offsetof(PyTypeObject, tp_free)}, +{offsetof(PyNumberMethods, nb_matrix_multiply), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyNumberMethods, nb_inplace_matrix_multiply), offsetof(PyTypeObject, tp_as_number)}, +{offsetof(PyAsyncMethods, am_await), offsetof(PyTypeObject, tp_as_async)}, +{offsetof(PyAsyncMethods, am_aiter), offsetof(PyTypeObject, tp_as_async)}, +{offsetof(PyAsyncMethods, am_anext), offsetof(PyTypeObject, tp_as_async)}, +{-1, offsetof(PyTypeObject, tp_finalize)}, +{offsetof(PyAsyncMethods, am_send), offsetof(PyTypeObject, tp_as_async)}, diff --git a/contrib/tools/python3/src/Objects/unicodeobject.c b/contrib/tools/python3/src/Objects/unicodeobject.c index 7767d140e6..077cf8d7f4 100644 --- a/contrib/tools/python3/src/Objects/unicodeobject.c +++ b/contrib/tools/python3/src/Objects/unicodeobject.c @@ -40,17 +40,18 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define PY_SSIZE_T_CLEAN #include "Python.h" -#include "pycore_abstract.h" // _PyIndex_Check() -#include "pycore_bytes_methods.h" -#include "pycore_fileutils.h" -#include "pycore_initconfig.h" -#include "pycore_interp.h" // PyInterpreterState.fs_codec -#include "pycore_object.h" -#include "pycore_pathconfig.h" -#include "pycore_pylifecycle.h" -#include "pycore_pystate.h" // _PyInterpreterState_GET() -#include "ucnhash.h" -#include "stringlib/eq.h" +#include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_atomic_funcs.h" // _Py_atomic_size_get() +#include "pycore_bytes_methods.h" // _Py_bytes_lower() +#include "pycore_format.h" // F_LJUST +#include "pycore_initconfig.h" // _PyStatus_OK() +#include "pycore_interp.h" // PyInterpreterState.fs_codec +#include "pycore_object.h" // _PyObject_GC_TRACK() +#include "pycore_pathconfig.h" // _Py_DumpPathConfig() +#include "pycore_pylifecycle.h" // _Py_SetFileSystemEncoding() +#include "pycore_pystate.h" // _PyInterpreterState_GET() +#include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI +#include "stringlib/eq.h" // unicode_eq() #ifdef MS_WINDOWS #include <windows.h> @@ -60,8 +61,8 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "pycore_fileutils.h" // _Py_LocaleUsesNonUnicodeWchar() #endif -/* Uncomment to display statistics on interned strings at exit when - using Valgrind or Insecure++. */ +/* Uncomment to display statistics on interned strings at exit + in _PyUnicode_ClearInterned(). */ /* #define INTERNED_STATS 1 */ @@ -210,7 +211,10 @@ extern "C" { # define OVERALLOCATE_FACTOR 4 #endif -#define INTERNED_STRINGS +/* bpo-40521: Interned strings are shared by all interpreters. */ +#ifndef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS +# define INTERNED_STRINGS +#endif /* This dictionary holds all interned unicode strings. Note that references to strings in this dictionary are *not* counted in the string's ob_refcnt. @@ -224,26 +228,36 @@ extern "C" { static PyObject *interned = NULL; #endif -/* The empty Unicode object is shared to improve performance. */ -static PyObject *unicode_empty = NULL; +static struct _Py_unicode_state* +get_unicode_state(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + return &interp->unicode; +} -#define _Py_INCREF_UNICODE_EMPTY() \ - do { \ - if (unicode_empty != NULL) \ - Py_INCREF(unicode_empty); \ - else { \ - unicode_empty = PyUnicode_New(0, 0); \ - if (unicode_empty != NULL) { \ - Py_INCREF(unicode_empty); \ - assert(_PyUnicode_CheckConsistency(unicode_empty, 1)); \ - } \ - } \ - } while (0) -#define _Py_RETURN_UNICODE_EMPTY() \ - do { \ - _Py_INCREF_UNICODE_EMPTY(); \ - return unicode_empty; \ +// Return a borrowed reference to the empty string singleton. +static inline PyObject* unicode_get_empty(void) +{ + struct _Py_unicode_state *state = get_unicode_state(); + // unicode_get_empty() must not be called before _PyUnicode_Init() + // or after _PyUnicode_Fini() + assert(state->empty_string != NULL); + return state->empty_string; +} + + +// Return a strong reference to the empty string singleton. +static inline PyObject* unicode_new_empty(void) +{ + PyObject *empty = unicode_get_empty(); + Py_INCREF(empty); + return empty; +} + +#define _Py_RETURN_UNICODE_EMPTY() \ + do { \ + return unicode_new_empty(); \ } while (0) static inline void @@ -294,17 +308,6 @@ unicode_decode_utf8(const char *s, Py_ssize_t size, _Py_error_handler error_handler, const char *errors, Py_ssize_t *consumed); -/* List of static strings. */ -static _Py_Identifier *static_strings = NULL; - -#define LATIN1_SINGLETONS - -#ifdef LATIN1_SINGLETONS -/* Single character Unicode strings in the Latin-1 range are being - shared as well. */ -static PyObject *unicode_latin1[256] = {NULL}; -#endif - /* Fast detection of the most frequent whitespace characters */ const unsigned char _Py_ascii_whitespace[] = { 0, 0, 0, 0, 0, 0, 0, 0, @@ -498,20 +501,6 @@ unicode_check_encoding_errors(const char *encoding, const char *errors) } -/* The max unicode value is always 0x10FFFF while using the PEP-393 API. - This function is kept for backward compatibility with the old API. */ -Py_UNICODE -PyUnicode_GetMax(void) -{ -#ifdef Py_UNICODE_WIDE - return 0x10FFFF; -#else - /* This is actually an illegal character, so it should - not be passed to unichr. */ - return 0xFFFF; -#endif -} - int _PyUnicode_CheckConsistency(PyObject *op, int check_content) { @@ -648,9 +637,8 @@ unicode_result_wchar(PyObject *unicode) if (len == 1) { wchar_t ch = _PyUnicode_WSTR(unicode)[0]; if ((Py_UCS4)ch < 256) { - PyObject *latin1_char = get_latin1_char((unsigned char)ch); Py_DECREF(unicode); - return latin1_char; + return get_latin1_char((unsigned char)ch); } } @@ -675,20 +663,21 @@ unicode_result_ready(PyObject *unicode) length = PyUnicode_GET_LENGTH(unicode); if (length == 0) { - if (unicode != unicode_empty) { + PyObject *empty = unicode_get_empty(); + if (unicode != empty) { Py_DECREF(unicode); - _Py_RETURN_UNICODE_EMPTY(); + Py_INCREF(empty); } - return unicode_empty; + return empty; } -#ifdef LATIN1_SINGLETONS if (length == 1) { - const void *data = PyUnicode_DATA(unicode); int kind = PyUnicode_KIND(unicode); - Py_UCS4 ch = PyUnicode_READ(kind, data, 0); - if (ch < 256) { - PyObject *latin1_char = unicode_latin1[ch]; + if (kind == PyUnicode_1BYTE_KIND) { + const Py_UCS1 *data = PyUnicode_1BYTE_DATA(unicode); + Py_UCS1 ch = data[0]; + struct _Py_unicode_state *state = get_unicode_state(); + PyObject *latin1_char = state->latin1[ch]; if (latin1_char != NULL) { if (unicode != latin1_char) { Py_INCREF(latin1_char); @@ -699,12 +688,14 @@ unicode_result_ready(PyObject *unicode) else { assert(_PyUnicode_CheckConsistency(unicode, 1)); Py_INCREF(unicode); - unicode_latin1[ch] = unicode; + state->latin1[ch] = unicode; return unicode; } } + else { + assert(PyUnicode_READ_CHAR(unicode, 0) >= 256); + } } -#endif assert(_PyUnicode_CheckConsistency(unicode, 1)); return unicode; @@ -867,7 +858,7 @@ xmlcharrefreplace(_PyBytesWriter *writer, char *str, to keep things simple, we use a single bitmask, using the least 5 bits from each unicode characters as the bit index. */ -/* the linebreak mask is set up by Unicode_Init below */ +/* the linebreak mask is set up by _PyUnicode_Init() below */ #if LONG_BIT >= 128 #define BLOOM_WIDTH 128 @@ -941,6 +932,8 @@ ensure_unicode(PyObject *obj) /* Compilation of templated routines */ +#define STRINGLIB_GET_EMPTY() unicode_get_empty() + #include "stringlib/asciilib.h" #include "stringlib/fastsearch.h" #include "stringlib/partition.h" @@ -989,6 +982,8 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS #include "stringlib/undef.h" _Py_COMP_DIAG_POP +#undef STRINGLIB_GET_EMPTY + /* --- Unicode Object ----------------------------------------------------- */ static inline Py_ssize_t @@ -1070,7 +1065,7 @@ resize_compact(PyObject *unicode, Py_ssize_t length) new_size = (struct_size + (length + 1) * char_size); if (_PyUnicode_HAS_UTF8_MEMORY(unicode)) { - PyObject_DEL(_PyUnicode_UTF8(unicode)); + PyObject_Free(_PyUnicode_UTF8(unicode)); _PyUnicode_UTF8(unicode) = NULL; _PyUnicode_UTF8_LENGTH(unicode) = 0; } @@ -1081,7 +1076,7 @@ resize_compact(PyObject *unicode, Py_ssize_t length) _Py_ForgetReference(unicode); #endif - new_unicode = (PyObject *)PyObject_REALLOC(unicode, new_size); + new_unicode = (PyObject *)PyObject_Realloc(unicode, new_size); if (new_unicode == NULL) { _Py_NewReference(unicode); PyErr_NoMemory(); @@ -1097,7 +1092,7 @@ resize_compact(PyObject *unicode, Py_ssize_t length) _PyUnicode_WSTR_LENGTH(unicode) = length; } else if (_PyUnicode_HAS_WSTR_MEMORY(unicode)) { - PyObject_DEL(_PyUnicode_WSTR(unicode)); + PyObject_Free(_PyUnicode_WSTR(unicode)); _PyUnicode_WSTR(unicode) = NULL; if (!PyUnicode_IS_ASCII(unicode)) _PyUnicode_WSTR_LENGTH(unicode) = 0; @@ -1140,12 +1135,12 @@ resize_inplace(PyObject *unicode, Py_ssize_t length) if (!share_utf8 && _PyUnicode_HAS_UTF8_MEMORY(unicode)) { - PyObject_DEL(_PyUnicode_UTF8(unicode)); + PyObject_Free(_PyUnicode_UTF8(unicode)); _PyUnicode_UTF8(unicode) = NULL; _PyUnicode_UTF8_LENGTH(unicode) = 0; } - data = (PyObject *)PyObject_REALLOC(data, new_size); + data = (PyObject *)PyObject_Realloc(data, new_size); if (data == NULL) { PyErr_NoMemory(); return -1; @@ -1178,7 +1173,7 @@ resize_inplace(PyObject *unicode, Py_ssize_t length) } new_size = sizeof(wchar_t) * (length + 1); wstr = _PyUnicode_WSTR(unicode); - wstr = PyObject_REALLOC(wstr, new_size); + wstr = PyObject_Realloc(wstr, new_size); if (!wstr) { PyErr_NoMemory(); return -1; @@ -1237,9 +1232,8 @@ _PyUnicode_New(Py_ssize_t length) size_t new_size; /* Optimization for empty strings */ - if (length == 0 && unicode_empty != NULL) { - Py_INCREF(unicode_empty); - return (PyUnicodeObject*)unicode_empty; + if (length == 0) { + return (PyUnicodeObject *)unicode_new_empty(); } /* Ensure we won't overflow the size. */ @@ -1269,7 +1263,7 @@ _PyUnicode_New(Py_ssize_t length) _PyUnicode_UTF8(unicode) = NULL; _PyUnicode_UTF8_LENGTH(unicode) = 0; - _PyUnicode_WSTR(unicode) = (Py_UNICODE*) PyObject_MALLOC(new_size); + _PyUnicode_WSTR(unicode) = (Py_UNICODE*) PyObject_Malloc(new_size); if (!_PyUnicode_WSTR(unicode)) { Py_DECREF(unicode); PyErr_NoMemory(); @@ -1369,27 +1363,51 @@ _PyUnicode_Dump(PyObject *op) } else data = unicode->data.any; - printf("%s: len=%" PY_FORMAT_SIZE_T "u, ", - unicode_kind_name(op), ascii->length); + printf("%s: len=%zu, ", unicode_kind_name(op), ascii->length); if (ascii->wstr == data) printf("shared "); printf("wstr=%p", (void *)ascii->wstr); if (!(ascii->state.ascii == 1 && ascii->state.compact == 1)) { - printf(" (%" PY_FORMAT_SIZE_T "u), ", compact->wstr_length); - if (!ascii->state.compact && compact->utf8 == unicode->data.any) + printf(" (%zu), ", compact->wstr_length); + if (!ascii->state.compact && compact->utf8 == unicode->data.any) { printf("shared "); - printf("utf8=%p (%" PY_FORMAT_SIZE_T "u)", - (void *)compact->utf8, compact->utf8_length); + } + printf("utf8=%p (%zu)", (void *)compact->utf8, compact->utf8_length); } printf(", data=%p\n", data); } #endif +static int +unicode_create_empty_string_singleton(struct _Py_unicode_state *state) +{ + // Use size=1 rather than size=0, so PyUnicode_New(0, maxchar) can be + // optimized to always use state->empty_string without having to check if + // it is NULL or not. + PyObject *empty = PyUnicode_New(1, 0); + if (empty == NULL) { + return -1; + } + PyUnicode_1BYTE_DATA(empty)[0] = 0; + _PyUnicode_LENGTH(empty) = 0; + assert(_PyUnicode_CheckConsistency(empty, 1)); + + assert(state->empty_string == NULL); + state->empty_string = empty; + return 0; +} + + PyObject * PyUnicode_New(Py_ssize_t size, Py_UCS4 maxchar) { + /* Optimization for empty strings */ + if (size == 0) { + return unicode_new_empty(); + } + PyObject *obj; PyCompactUnicodeObject *unicode; void *data; @@ -1398,12 +1416,6 @@ PyUnicode_New(Py_ssize_t size, Py_UCS4 maxchar) Py_ssize_t char_size; Py_ssize_t struct_size; - /* Optimization for empty strings */ - if (size == 0 && unicode_empty != NULL) { - Py_INCREF(unicode_empty); - return unicode_empty; - } - is_ascii = 0; is_sharing = 0; struct_size = sizeof(PyCompactUnicodeObject); @@ -1448,12 +1460,11 @@ PyUnicode_New(Py_ssize_t size, Py_UCS4 maxchar) * PyObject_New() so we are able to allocate space for the object and * it's data buffer. */ - obj = (PyObject *) PyObject_MALLOC(struct_size + (size + 1) * char_size); - if (obj == NULL) + obj = (PyObject *) PyObject_Malloc(struct_size + (size + 1) * char_size); + if (obj == NULL) { return PyErr_NoMemory(); - obj = PyObject_INIT(obj, &PyUnicode_Type); - if (obj == NULL) - return NULL; + } + _PyObject_Init(obj, &PyUnicode_Type); unicode = (PyCompactUnicodeObject *)obj; if (is_ascii) @@ -1831,7 +1842,7 @@ _PyUnicode_Ready(PyObject *unicode) return -1; if (maxchar < 256) { - _PyUnicode_DATA_ANY(unicode) = PyObject_MALLOC(_PyUnicode_WSTR_LENGTH(unicode) + 1); + _PyUnicode_DATA_ANY(unicode) = PyObject_Malloc(_PyUnicode_WSTR_LENGTH(unicode) + 1); if (!_PyUnicode_DATA_ANY(unicode)) { PyErr_NoMemory(); return -1; @@ -1852,7 +1863,7 @@ _PyUnicode_Ready(PyObject *unicode) _PyUnicode_UTF8(unicode) = NULL; _PyUnicode_UTF8_LENGTH(unicode) = 0; } - PyObject_FREE(_PyUnicode_WSTR(unicode)); + PyObject_Free(_PyUnicode_WSTR(unicode)); _PyUnicode_WSTR(unicode) = NULL; _PyUnicode_WSTR_LENGTH(unicode) = 0; } @@ -1872,7 +1883,7 @@ _PyUnicode_Ready(PyObject *unicode) _PyUnicode_UTF8_LENGTH(unicode) = 0; #else /* sizeof(wchar_t) == 4 */ - _PyUnicode_DATA_ANY(unicode) = PyObject_MALLOC( + _PyUnicode_DATA_ANY(unicode) = PyObject_Malloc( 2 * (_PyUnicode_WSTR_LENGTH(unicode) + 1)); if (!_PyUnicode_DATA_ANY(unicode)) { PyErr_NoMemory(); @@ -1886,7 +1897,7 @@ _PyUnicode_Ready(PyObject *unicode) _PyUnicode_STATE(unicode).kind = PyUnicode_2BYTE_KIND; _PyUnicode_UTF8(unicode) = NULL; _PyUnicode_UTF8_LENGTH(unicode) = 0; - PyObject_FREE(_PyUnicode_WSTR(unicode)); + PyObject_Free(_PyUnicode_WSTR(unicode)); _PyUnicode_WSTR(unicode) = NULL; _PyUnicode_WSTR_LENGTH(unicode) = 0; #endif @@ -1901,7 +1912,7 @@ _PyUnicode_Ready(PyObject *unicode) PyErr_NoMemory(); return -1; } - _PyUnicode_DATA_ANY(unicode) = PyObject_MALLOC(4 * (length_wo_surrogates + 1)); + _PyUnicode_DATA_ANY(unicode) = PyObject_Malloc(4 * (length_wo_surrogates + 1)); if (!_PyUnicode_DATA_ANY(unicode)) { PyErr_NoMemory(); return -1; @@ -1913,7 +1924,7 @@ _PyUnicode_Ready(PyObject *unicode) /* unicode_convert_wchar_to_ucs4() requires a ready string */ _PyUnicode_STATE(unicode).ready = 1; unicode_convert_wchar_to_ucs4(_PyUnicode_WSTR(unicode), end, unicode); - PyObject_FREE(_PyUnicode_WSTR(unicode)); + PyObject_Free(_PyUnicode_WSTR(unicode)); _PyUnicode_WSTR(unicode) = NULL; _PyUnicode_WSTR_LENGTH(unicode) = 0; #else @@ -1940,15 +1951,24 @@ unicode_dealloc(PyObject *unicode) break; case SSTATE_INTERNED_MORTAL: - /* revive dead object temporarily for DelItem */ - Py_SET_REFCNT(unicode, 3); + { #ifdef INTERNED_STRINGS + /* Revive the dead object temporarily. PyDict_DelItem() removes two + references (key and value) which were ignored by + PyUnicode_InternInPlace(). Use refcnt=3 rather than refcnt=2 + to prevent calling unicode_dealloc() again. Adjust refcnt after + PyDict_DelItem(). */ + assert(Py_REFCNT(unicode) == 0); + Py_SET_REFCNT(unicode, 3); if (PyDict_DelItem(interned, unicode) != 0) { _PyErr_WriteUnraisableMsg("deletion of interned string failed", NULL); } + assert(Py_REFCNT(unicode) == 1); + Py_SET_REFCNT(unicode, 0); #endif break; + } case SSTATE_INTERNED_IMMORTAL: _PyObject_ASSERT_FAILED_MSG(unicode, "Immortal interned string died"); @@ -1959,13 +1979,13 @@ unicode_dealloc(PyObject *unicode) } if (_PyUnicode_HAS_WSTR_MEMORY(unicode)) { - PyObject_DEL(_PyUnicode_WSTR(unicode)); + PyObject_Free(_PyUnicode_WSTR(unicode)); } if (_PyUnicode_HAS_UTF8_MEMORY(unicode)) { - PyObject_DEL(_PyUnicode_UTF8(unicode)); + PyObject_Free(_PyUnicode_UTF8(unicode)); } if (!PyUnicode_IS_COMPACT(unicode) && _PyUnicode_DATA_ANY(unicode)) { - PyObject_DEL(_PyUnicode_DATA_ANY(unicode)); + PyObject_Free(_PyUnicode_DATA_ANY(unicode)); } Py_TYPE(unicode)->tp_free(unicode); @@ -1975,18 +1995,18 @@ unicode_dealloc(PyObject *unicode) static int unicode_is_singleton(PyObject *unicode) { - if (unicode == unicode_empty) { + struct _Py_unicode_state *state = get_unicode_state(); + if (unicode == state->empty_string) { return 1; } -#ifdef LATIN1_SINGLETONS PyASCIIObject *ascii = (PyASCIIObject *)unicode; if (ascii->state.kind != PyUnicode_WCHAR_KIND && ascii->length == 1) { Py_UCS4 ch = PyUnicode_READ_CHAR(unicode, 0); - if (ch < 256 && unicode_latin1[ch] == unicode) + if (ch < 256 && state->latin1[ch] == unicode) { return 1; + } } -#endif return 0; } #endif @@ -2031,10 +2051,8 @@ unicode_resize(PyObject **p_unicode, Py_ssize_t length) return 0; if (length == 0) { - _Py_INCREF_UNICODE_EMPTY(); - if (!unicode_empty) - return -1; - Py_SETREF(*p_unicode, unicode_empty); + PyObject *empty = unicode_new_empty(); + Py_SETREF(*p_unicode, empty); return 0; } @@ -2126,17 +2144,15 @@ unicode_write_cstr(PyObject *unicode, Py_ssize_t index, } static PyObject* -get_latin1_char(unsigned char ch) +get_latin1_char(Py_UCS1 ch) { - PyObject *unicode; + struct _Py_unicode_state *state = get_unicode_state(); -#ifdef LATIN1_SINGLETONS - unicode = unicode_latin1[ch]; + PyObject *unicode = state->latin1[ch]; if (unicode) { Py_INCREF(unicode); return unicode; } -#endif unicode = PyUnicode_New(1, ch); if (!unicode) { @@ -2146,10 +2162,8 @@ get_latin1_char(unsigned char ch) PyUnicode_1BYTE_DATA(unicode)[0] = ch; assert(_PyUnicode_CheckConsistency(unicode, 1)); -#ifdef LATIN1_SINGLETONS Py_INCREF(unicode); - unicode_latin1[ch] = unicode; -#endif + state->latin1[ch] = unicode; return unicode; } @@ -2160,8 +2174,9 @@ unicode_char(Py_UCS4 ch) assert(ch <= MAX_UNICODE); - if (ch < 256) + if (ch < 256) { return get_latin1_char(ch); + } unicode = PyUnicode_New(1, ch); if (unicode == NULL) @@ -2181,8 +2196,16 @@ unicode_char(Py_UCS4 ch) PyObject * PyUnicode_FromUnicode(const Py_UNICODE *u, Py_ssize_t size) { - if (u == NULL) + if (u == NULL) { + if (size > 0) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_FromUnicode(NULL, size) is deprecated; " + "use PyUnicode_New() instead", 1) < 0) { + return NULL; + } + } return (PyObject*)_PyUnicode_New(size); + } if (size < 0) { PyErr_BadInternalCall(); @@ -2282,10 +2305,19 @@ PyUnicode_FromStringAndSize(const char *u, Py_ssize_t size) "Negative size passed to PyUnicode_FromStringAndSize"); return NULL; } - if (u != NULL) + if (u != NULL) { return PyUnicode_DecodeUTF8Stateful(u, size, NULL, NULL); - else + } + else { + if (size > 0) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_FromStringAndSize(NULL, size) is deprecated; " + "use PyUnicode_New() instead", 1) < 0) { + return NULL; + } + } return (PyObject *)_PyUnicode_New(size); + } } PyObject * @@ -2299,36 +2331,84 @@ PyUnicode_FromString(const char *u) return PyUnicode_DecodeUTF8Stateful(u, (Py_ssize_t)size, NULL, NULL); } + PyObject * _PyUnicode_FromId(_Py_Identifier *id) { - if (!id->object) { - id->object = PyUnicode_DecodeUTF8Stateful(id->string, - strlen(id->string), - NULL, NULL); - if (!id->object) + PyInterpreterState *interp = _PyInterpreterState_GET(); + struct _Py_unicode_ids *ids = &interp->unicode.ids; + + Py_ssize_t index = _Py_atomic_size_get(&id->index); + if (index < 0) { + struct _Py_unicode_runtime_ids *rt_ids = &interp->runtime->unicode_ids; + + PyThread_acquire_lock(rt_ids->lock, WAIT_LOCK); + // Check again to detect concurrent access. Another thread can have + // initialized the index while this thread waited for the lock. + index = _Py_atomic_size_get(&id->index); + if (index < 0) { + assert(rt_ids->next_index < PY_SSIZE_T_MAX); + index = rt_ids->next_index; + rt_ids->next_index++; + _Py_atomic_size_set(&id->index, index); + } + PyThread_release_lock(rt_ids->lock); + } + assert(index >= 0); + + PyObject *obj; + if (index < ids->size) { + obj = ids->array[index]; + if (obj) { + // Return a borrowed reference + return obj; + } + } + + obj = PyUnicode_DecodeUTF8Stateful(id->string, strlen(id->string), + NULL, NULL); + if (!obj) { + return NULL; + } + PyUnicode_InternInPlace(&obj); + + if (index >= ids->size) { + // Overallocate to reduce the number of realloc + Py_ssize_t new_size = Py_MAX(index * 2, 16); + Py_ssize_t item_size = sizeof(ids->array[0]); + PyObject **new_array = PyMem_Realloc(ids->array, new_size * item_size); + if (new_array == NULL) { + PyErr_NoMemory(); return NULL; - PyUnicode_InternInPlace(&id->object); - assert(!id->next); - id->next = static_strings; - static_strings = id; + } + memset(&new_array[ids->size], 0, (new_size - ids->size) * item_size); + ids->array = new_array; + ids->size = new_size; } - return id->object; + + // The array stores a strong reference + ids->array[index] = obj; + + // Return a borrowed reference + return obj; } + static void -unicode_clear_static_strings(void) +unicode_clear_identifiers(struct _Py_unicode_state *state) { - _Py_Identifier *tmp, *s = static_strings; - while (s) { - Py_CLEAR(s->object); - tmp = s->next; - s->next = NULL; - s = tmp; + struct _Py_unicode_ids *ids = &state->ids; + for (Py_ssize_t i=0; i < ids->size; i++) { + Py_XDECREF(ids->array[i]); } - static_strings = NULL; + ids->size = 0; + PyMem_Free(ids->array); + ids->array = NULL; + // Don't reset _PyRuntime next_index: _Py_Identifier.id remains valid + // after Py_Finalize(). } + /* Internal function, doesn't check maximum character */ PyObject* @@ -2371,11 +2451,13 @@ _PyUnicode_FromUCS1(const Py_UCS1* u, Py_ssize_t size) PyObject *res; unsigned char max_char; - if (size == 0) + if (size == 0) { _Py_RETURN_UNICODE_EMPTY(); + } assert(size > 0); - if (size == 1) + if (size == 1) { return get_latin1_char(u[0]); + } max_char = ucs1lib_find_max_char(u, u + size); res = PyUnicode_New(size, max_char); @@ -2866,35 +2948,35 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, Py_ssize_t arglen; if (*f == 'u') { - if (longflag) - len = sprintf(buffer, "%lu", - va_arg(*vargs, unsigned long)); - else if (longlongflag) - len = sprintf(buffer, "%llu", - va_arg(*vargs, unsigned long long)); - else if (size_tflag) - len = sprintf(buffer, "%" PY_FORMAT_SIZE_T "u", - va_arg(*vargs, size_t)); - else - len = sprintf(buffer, "%u", - va_arg(*vargs, unsigned int)); + if (longflag) { + len = sprintf(buffer, "%lu", va_arg(*vargs, unsigned long)); + } + else if (longlongflag) { + len = sprintf(buffer, "%llu", va_arg(*vargs, unsigned long long)); + } + else if (size_tflag) { + len = sprintf(buffer, "%zu", va_arg(*vargs, size_t)); + } + else { + len = sprintf(buffer, "%u", va_arg(*vargs, unsigned int)); + } } else if (*f == 'x') { len = sprintf(buffer, "%x", va_arg(*vargs, int)); } else { - if (longflag) - len = sprintf(buffer, "%li", - va_arg(*vargs, long)); - else if (longlongflag) - len = sprintf(buffer, "%lli", - va_arg(*vargs, long long)); - else if (size_tflag) - len = sprintf(buffer, "%" PY_FORMAT_SIZE_T "i", - va_arg(*vargs, Py_ssize_t)); - else - len = sprintf(buffer, "%i", - va_arg(*vargs, int)); + if (longflag) { + len = sprintf(buffer, "%li", va_arg(*vargs, long)); + } + else if (longlongflag) { + len = sprintf(buffer, "%lli", va_arg(*vargs, long long)); + } + else if (size_tflag) { + len = sprintf(buffer, "%zi", va_arg(*vargs, Py_ssize_t)); + } + else { + len = sprintf(buffer, "%i", va_arg(*vargs, int)); + } } assert(len >= 0); @@ -3134,9 +3216,11 @@ unicode_get_widechar_size(PyObject *unicode) assert(unicode != NULL); assert(_PyUnicode_CHECK(unicode)); +#if USE_UNICODE_WCHAR_CACHE if (_PyUnicode_WSTR(unicode) != NULL) { return PyUnicode_WSTR_LENGTH(unicode); } +#endif /* USE_UNICODE_WCHAR_CACHE */ assert(PyUnicode_IS_READY(unicode)); res = _PyUnicode_LENGTH(unicode); @@ -3157,16 +3241,21 @@ unicode_get_widechar_size(PyObject *unicode) static void unicode_copy_as_widechar(PyObject *unicode, wchar_t *w, Py_ssize_t size) { - const wchar_t *wstr; - assert(unicode != NULL); assert(_PyUnicode_CHECK(unicode)); - wstr = _PyUnicode_WSTR(unicode); +#if USE_UNICODE_WCHAR_CACHE + const wchar_t *wstr = _PyUnicode_WSTR(unicode); if (wstr != NULL) { memcpy(w, wstr, size * sizeof(wchar_t)); return; } +#else /* USE_UNICODE_WCHAR_CACHE */ + if (PyUnicode_KIND(unicode) == sizeof(wchar_t)) { + memcpy(w, PyUnicode_DATA(unicode), size * sizeof(wchar_t)); + return; + } +#endif /* USE_UNICODE_WCHAR_CACHE */ assert(PyUnicode_IS_READY(unicode)); if (PyUnicode_KIND(unicode) == PyUnicode_1BYTE_KIND) { @@ -3293,7 +3382,7 @@ PyUnicode_AsWideCharString(PyObject *unicode, *size = buflen; } else if (wcslen(buffer) != (size_t)buflen) { - PyMem_FREE(buffer); + PyMem_Free(buffer); PyErr_SetString(PyExc_ValueError, "embedded null character"); return NULL; @@ -3303,6 +3392,74 @@ PyUnicode_AsWideCharString(PyObject *unicode, #endif /* HAVE_WCHAR_H */ +int +_PyUnicode_WideCharString_Converter(PyObject *obj, void *ptr) +{ + wchar_t **p = (wchar_t **)ptr; + if (obj == NULL) { +#if !USE_UNICODE_WCHAR_CACHE + PyMem_Free(*p); +#endif /* USE_UNICODE_WCHAR_CACHE */ + *p = NULL; + return 1; + } + if (PyUnicode_Check(obj)) { +#if USE_UNICODE_WCHAR_CACHE + *p = (wchar_t *)_PyUnicode_AsUnicode(obj); + if (*p == NULL) { + return 0; + } + return 1; +#else /* USE_UNICODE_WCHAR_CACHE */ + *p = PyUnicode_AsWideCharString(obj, NULL); + if (*p == NULL) { + return 0; + } + return Py_CLEANUP_SUPPORTED; +#endif /* USE_UNICODE_WCHAR_CACHE */ + } + PyErr_Format(PyExc_TypeError, + "argument must be str, not %.50s", + Py_TYPE(obj)->tp_name); + return 0; +} + +int +_PyUnicode_WideCharString_Opt_Converter(PyObject *obj, void *ptr) +{ + wchar_t **p = (wchar_t **)ptr; + if (obj == NULL) { +#if !USE_UNICODE_WCHAR_CACHE + PyMem_Free(*p); +#endif /* USE_UNICODE_WCHAR_CACHE */ + *p = NULL; + return 1; + } + if (obj == Py_None) { + *p = NULL; + return 1; + } + if (PyUnicode_Check(obj)) { +#if USE_UNICODE_WCHAR_CACHE + *p = (wchar_t *)_PyUnicode_AsUnicode(obj); + if (*p == NULL) { + return 0; + } + return 1; +#else /* USE_UNICODE_WCHAR_CACHE */ + *p = PyUnicode_AsWideCharString(obj, NULL); + if (*p == NULL) { + return 0; + } + return Py_CLEANUP_SUPPORTED; +#endif /* USE_UNICODE_WCHAR_CACHE */ + } + PyErr_Format(PyExc_TypeError, + "argument must be str or None, not %.50s", + Py_TYPE(obj)->tp_name); + return 0; +} + PyObject * PyUnicode_FromOrdinal(int ordinal) { @@ -4126,7 +4283,7 @@ PyUnicode_AsUnicodeAndSize(PyObject *unicode, Py_ssize_t *size) PyErr_NoMemory(); return NULL; } - w = (wchar_t *) PyObject_MALLOC(sizeof(wchar_t) * (wlen + 1)); + w = (wchar_t *) PyObject_Malloc(sizeof(wchar_t) * (wlen + 1)); if (w == NULL) { PyErr_NoMemory(); return NULL; @@ -4316,7 +4473,6 @@ unicode_decode_call_errorhandler_wchar( Py_ssize_t requiredsize; Py_ssize_t newpos; PyObject *inputobj = NULL; - wchar_t *repwstr; Py_ssize_t repwlen; if (*errorHandler == NULL) { @@ -4362,12 +4518,19 @@ unicode_decode_call_errorhandler_wchar( goto onError; } +#if USE_UNICODE_WCHAR_CACHE _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS - repwstr = PyUnicode_AsUnicodeAndSize(repunicode, &repwlen); + repwlen = PyUnicode_GetSize(repunicode); + if (repwlen < 0) + goto onError; _Py_COMP_DIAG_POP - if (repwstr == NULL) +#else /* USE_UNICODE_WCHAR_CACHE */ + repwlen = PyUnicode_AsWideChar(repunicode, NULL, 0); + if (repwlen < 0) goto onError; + repwlen--; +#endif /* USE_UNICODE_WCHAR_CACHE */ /* need more space? (at least enough for what we have+the replacement+the rest of the string (starting at the new input position), so we won't have to check space @@ -4387,7 +4550,7 @@ _Py_COMP_DIAG_POP goto onError; } } - wcsncpy(*buf + *outpos, repwstr, repwlen); + PyUnicode_AsWideChar(repunicode, *buf + *outpos, repwlen); *outpos += repwlen; *endinpos = newpos; *inptr = *input + newpos; @@ -4950,45 +5113,36 @@ PyUnicode_DecodeUTF8(const char *s, #include "stringlib/codecs.h" #include "stringlib/undef.h" -/* Mask to quickly check whether a C 'long' contains a +/* Mask to quickly check whether a C 'size_t' contains a non-ASCII, UTF8-encoded char. */ -#if (SIZEOF_LONG == 8) -# define ASCII_CHAR_MASK 0x8080808080808080UL -#elif (SIZEOF_LONG == 4) -# define ASCII_CHAR_MASK 0x80808080UL +#if (SIZEOF_SIZE_T == 8) +# define ASCII_CHAR_MASK 0x8080808080808080ULL +#elif (SIZEOF_SIZE_T == 4) +# define ASCII_CHAR_MASK 0x80808080U #else -# error C 'long' size should be either 4 or 8! +# error C 'size_t' size should be either 4 or 8! #endif static Py_ssize_t ascii_decode(const char *start, const char *end, Py_UCS1 *dest) { const char *p = start; - const char *aligned_end = (const char *) _Py_ALIGN_DOWN(end, SIZEOF_LONG); - - /* - * Issue #17237: m68k is a bit different from most architectures in - * that objects do not use "natural alignment" - for example, int and - * long are only aligned at 2-byte boundaries. Therefore the assert() - * won't work; also, tests have shown that skipping the "optimised - * version" will even speed up m68k. - */ -#if !defined(__m68k__) -#if SIZEOF_LONG <= SIZEOF_VOID_P - assert(_Py_IS_ALIGNED(dest, SIZEOF_LONG)); - if (_Py_IS_ALIGNED(p, SIZEOF_LONG)) { + +#if SIZEOF_SIZE_T <= SIZEOF_VOID_P + assert(_Py_IS_ALIGNED(dest, ALIGNOF_SIZE_T)); + if (_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) { /* Fast path, see in STRINGLIB(utf8_decode) for an explanation. */ /* Help allocation */ const char *_p = p; Py_UCS1 * q = dest; - while (_p < aligned_end) { - unsigned long value = *(const unsigned long *) _p; + while (_p + SIZEOF_SIZE_T <= end) { + size_t value = *(const size_t *) _p; if (value & ASCII_CHAR_MASK) break; - *((unsigned long *)q) = value; - _p += SIZEOF_LONG; - q += SIZEOF_LONG; + *((size_t *)q) = value; + _p += SIZEOF_SIZE_T; + q += SIZEOF_SIZE_T; } p = _p; while (p < end) { @@ -4999,18 +5153,17 @@ ascii_decode(const char *start, const char *end, Py_UCS1 *dest) return p - start; } #endif -#endif while (p < end) { /* Fast path, see in STRINGLIB(utf8_decode) in stringlib/codecs.h for an explanation. */ - if (_Py_IS_ALIGNED(p, SIZEOF_LONG)) { + if (_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) { /* Help allocation */ const char *_p = p; - while (_p < aligned_end) { - unsigned long value = *(const unsigned long *) _p; + while (_p + SIZEOF_SIZE_T <= end) { + size_t value = *(const size_t *) _p; if (value & ASCII_CHAR_MASK) break; - _p += SIZEOF_LONG; + _p += SIZEOF_SIZE_T; } p = _p; if (_p == end) @@ -5037,8 +5190,9 @@ unicode_decode_utf8(const char *s, Py_ssize_t size, /* ASCII is equivalent to the first 128 ordinals in Unicode. */ if (size == 1 && (unsigned char)s[0] < 128) { - if (consumed) + if (consumed) { *consumed = 1; + } return get_latin1_char((unsigned char)s[0]); } @@ -5547,7 +5701,7 @@ unicode_fill_utf8(PyObject *unicode) PyBytes_AS_STRING(writer.buffer); Py_ssize_t len = end - start; - char *cache = PyObject_MALLOC(len + 1); + char *cache = PyObject_Malloc(len + 1); if (cache == NULL) { _PyBytesWriter_Dealloc(&writer); PyErr_NoMemory(); @@ -6268,7 +6422,7 @@ PyUnicode_AsUTF16String(PyObject *unicode) /* --- Unicode Escape Codec ----------------------------------------------- */ -static _PyUnicode_Name_CAPI *ucnhash_CAPI = NULL; +static _PyUnicode_Name_CAPI *ucnhash_capi = NULL; PyObject * _PyUnicode_DecodeUnicodeEscapeInternal(const char *s, @@ -6423,11 +6577,11 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s, /* \N{name} */ case 'N': - if (ucnhash_CAPI == NULL) { + if (ucnhash_capi == NULL) { /* load the unicode data module */ - ucnhash_CAPI = (_PyUnicode_Name_CAPI *)PyCapsule_Import( + ucnhash_capi = (_PyUnicode_Name_CAPI *)PyCapsule_Import( PyUnicodeData_CAPSULE_NAME, 1); - if (ucnhash_CAPI == NULL) { + if (ucnhash_capi == NULL) { PyErr_SetString( PyExc_UnicodeError, "\\N escapes not supported (can't load unicodedata module)" @@ -6455,7 +6609,7 @@ _PyUnicode_DecodeUnicodeEscapeInternal(const char *s, s++; ch = 0xffffffff; /* in case 'getcode' messes up */ if (namelen <= INT_MAX && - ucnhash_CAPI->getcode(NULL, start, (int)namelen, + ucnhash_capi->getcode(start, (int)namelen, &ch, 0)) { assert(ch <= MAX_UNICODE); WRITE_CHAR(ch); @@ -7254,8 +7408,9 @@ PyUnicode_DecodeASCII(const char *s, _Py_RETURN_UNICODE_EMPTY(); /* ASCII is equivalent to the first 128 ordinals in Unicode. */ - if (size == 1 && (unsigned char)s[0] < 128) + if (size == 1 && (unsigned char)s[0] < 128) { return get_latin1_char((unsigned char)s[0]); + } // Shortcut for simple case PyObject *u = PyUnicode_New(size, 127); @@ -7736,6 +7891,7 @@ encode_code_page_strict(UINT code_page, PyObject **outbytes, /* Create a substring so that we can get the UTF-16 representation of just the slice under consideration. */ PyObject *substring; + int ret = -1; assert(len > 0); @@ -7747,14 +7903,22 @@ encode_code_page_strict(UINT code_page, PyObject **outbytes, substring = PyUnicode_Substring(unicode, offset, offset+len); if (substring == NULL) return -1; +#if USE_UNICODE_WCHAR_CACHE _Py_COMP_DIAG_PUSH _Py_COMP_DIAG_IGNORE_DEPR_DECLS p = PyUnicode_AsUnicodeAndSize(substring, &size); -_Py_COMP_DIAG_POP if (p == NULL) { Py_DECREF(substring); return -1; } +_Py_COMP_DIAG_POP +#else /* USE_UNICODE_WCHAR_CACHE */ + p = PyUnicode_AsWideCharString(substring, &size); + Py_CLEAR(substring); + if (p == NULL) { + return -1; + } +#endif /* USE_UNICODE_WCHAR_CACHE */ assert(size <= INT_MAX); /* First get the size of the result */ @@ -7766,16 +7930,15 @@ _Py_COMP_DIAG_POP goto error; /* If we used a default char, then we failed! */ if (pusedDefaultChar && *pusedDefaultChar) { - Py_DECREF(substring); - return -2; + ret = -2; + goto done; } if (*outbytes == NULL) { /* Create string object */ *outbytes = PyBytes_FromStringAndSize(NULL, outsize); if (*outbytes == NULL) { - Py_DECREF(substring); - return -1; + goto done; } out = PyBytes_AS_STRING(*outbytes); } @@ -7784,12 +7947,10 @@ _Py_COMP_DIAG_POP const Py_ssize_t n = PyBytes_Size(*outbytes); if (outsize > PY_SSIZE_T_MAX - n) { PyErr_NoMemory(); - Py_DECREF(substring); - return -1; + goto done; } if (_PyBytes_Resize(outbytes, n + outsize) < 0) { - Py_DECREF(substring); - return -1; + goto done; } out = PyBytes_AS_STRING(*outbytes) + n; } @@ -7799,19 +7960,29 @@ _Py_COMP_DIAG_POP p, (int)size, out, outsize, NULL, pusedDefaultChar); - Py_CLEAR(substring); if (outsize <= 0) goto error; - if (pusedDefaultChar && *pusedDefaultChar) - return -2; - return 0; + if (pusedDefaultChar && *pusedDefaultChar) { + ret = -2; + goto done; + } + ret = 0; + +done: +#if USE_UNICODE_WCHAR_CACHE + Py_DECREF(substring); +#else /* USE_UNICODE_WCHAR_CACHE */ + PyMem_Free(p); +#endif /* USE_UNICODE_WCHAR_CACHE */ + return ret; error: - Py_XDECREF(substring); - if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) - return -2; + if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) { + ret = -2; + goto done; + } PyErr_SetFromWindowsErr(0); - return -1; + goto done; } /* @@ -8496,11 +8667,13 @@ PyUnicode_BuildEncodingMap(PyObject* string) } /* Create a three-level trie */ - result = PyObject_MALLOC(sizeof(struct encoding_map) + + result = PyObject_Malloc(sizeof(struct encoding_map) + 16*count2 + 128*count3 - 1); - if (!result) + if (!result) { return PyErr_NoMemory(); - PyObject_Init(result, &EncodingMapType); + } + + _PyObject_Init(result, &EncodingMapType); mresult = (struct encoding_map*)result; mresult->count2 = count2; mresult->count3 = count3; @@ -10161,7 +10334,7 @@ case_operation(PyObject *self, PyErr_SetString(PyExc_OverflowError, "string is too long"); return NULL; } - tmp = PyMem_MALLOC(sizeof(Py_UCS4) * 3 * length); + tmp = PyMem_Malloc(sizeof(Py_UCS4) * 3 * length); if (tmp == NULL) return PyErr_NoMemory(); newlength = perform(kind, data, length, tmp, &maxchar); @@ -10185,7 +10358,7 @@ case_operation(PyObject *self, Py_UNREACHABLE(); } leave: - PyMem_FREE(tmp); + PyMem_Free(tmp); return res; } @@ -10924,10 +11097,7 @@ replace(PyObject *self, PyObject *str1, } new_size = slen + n * (len2 - len1); if (new_size == 0) { - _Py_INCREF_UNICODE_EMPTY(); - if (!unicode_empty) - goto error; - u = unicode_empty; + u = unicode_new_empty(); goto done; } if (new_size > (PY_SSIZE_T_MAX / rkind)) { @@ -11003,11 +11173,11 @@ replace(PyObject *self, PyObject *str1, assert(release1 == (buf1 != PyUnicode_DATA(str1))); assert(release2 == (buf2 != PyUnicode_DATA(str2))); if (srelease) - PyMem_FREE((void *)sbuf); + PyMem_Free((void *)sbuf); if (release1) - PyMem_FREE((void *)buf1); + PyMem_Free((void *)buf1); if (release2) - PyMem_FREE((void *)buf2); + PyMem_Free((void *)buf2); assert(_PyUnicode_CheckConsistency(u, 1)); return u; @@ -11017,11 +11187,11 @@ replace(PyObject *self, PyObject *str1, assert(release1 == (buf1 != PyUnicode_DATA(str1))); assert(release2 == (buf2 != PyUnicode_DATA(str2))); if (srelease) - PyMem_FREE((void *)sbuf); + PyMem_Free((void *)sbuf); if (release1) - PyMem_FREE((void *)buf1); + PyMem_Free((void *)buf1); if (release2) - PyMem_FREE((void *)buf2); + PyMem_Free((void *)buf2); return unicode_result_unchanged(self); error: @@ -11029,11 +11199,11 @@ replace(PyObject *self, PyObject *str1, assert(release1 == (buf1 != PyUnicode_DATA(str1))); assert(release2 == (buf2 != PyUnicode_DATA(str2))); if (srelease) - PyMem_FREE((void *)sbuf); + PyMem_Free((void *)sbuf); if (release1) - PyMem_FREE((void *)buf1); + PyMem_Free((void *)buf1); if (release2) - PyMem_FREE((void *)buf2); + PyMem_Free((void *)buf2); return NULL; } @@ -11450,8 +11620,9 @@ _PyUnicode_EqualToASCIIId(PyObject *left, _Py_Identifier *right) #ifdef INTERNED_STRINGS assert(_PyUnicode_HASH(right_uni) != -1); Py_hash_t hash = _PyUnicode_HASH(left); - if (hash != -1 && hash != _PyUnicode_HASH(right_uni)) + if (hash != -1 && hash != _PyUnicode_HASH(right_uni)) { return 0; + } #endif return unicode_compare_eq(left, right_uni); @@ -11585,10 +11756,13 @@ PyUnicode_Concat(PyObject *left, PyObject *right) return NULL; /* Shortcuts */ - if (left == unicode_empty) + PyObject *empty = unicode_get_empty(); // Borrowed reference + if (left == empty) { return PyUnicode_FromObject(right); - if (right == unicode_empty) + } + if (right == empty) { return PyUnicode_FromObject(left); + } left_len = PyUnicode_GET_LENGTH(left); right_len = PyUnicode_GET_LENGTH(right); @@ -11639,14 +11813,16 @@ PyUnicode_Append(PyObject **p_left, PyObject *right) goto error; /* Shortcuts */ - if (left == unicode_empty) { + PyObject *empty = unicode_get_empty(); // Borrowed reference + if (left == empty) { Py_DECREF(left); Py_INCREF(right); *p_left = right; return; } - if (right == unicode_empty) + if (right == empty) { return; + } left_len = PyUnicode_GET_LENGTH(left); right_len = PyUnicode_GET_LENGTH(right); @@ -13343,14 +13519,8 @@ PyUnicode_Partition(PyObject *str_obj, PyObject *sep_obj) len1 = PyUnicode_GET_LENGTH(str_obj); len2 = PyUnicode_GET_LENGTH(sep_obj); if (kind1 < kind2 || len1 < len2) { - _Py_INCREF_UNICODE_EMPTY(); - if (!unicode_empty) - out = NULL; - else { - out = PyTuple_Pack(3, str_obj, unicode_empty, unicode_empty); - Py_DECREF(unicode_empty); - } - return out; + PyObject *empty = unicode_get_empty(); // Borrowed reference + return PyTuple_Pack(3, str_obj, empty, empty); } buf1 = PyUnicode_DATA(str_obj); buf2 = PyUnicode_DATA(sep_obj); @@ -13401,14 +13571,8 @@ PyUnicode_RPartition(PyObject *str_obj, PyObject *sep_obj) len1 = PyUnicode_GET_LENGTH(str_obj); len2 = PyUnicode_GET_LENGTH(sep_obj); if (kind1 < kind2 || len1 < len2) { - _Py_INCREF_UNICODE_EMPTY(); - if (!unicode_empty) - out = NULL; - else { - out = PyTuple_Pack(3, unicode_empty, unicode_empty, str_obj); - Py_DECREF(unicode_empty); - } - return out; + PyObject *empty = unicode_get_empty(); // Borrowed reference + return PyTuple_Pack(3, empty, empty, str_obj); } buf1 = PyUnicode_DATA(str_obj); buf2 = PyUnicode_DATA(sep_obj); @@ -14731,20 +14895,15 @@ mainformatlong(PyObject *v, /* make sure number is a type of integer for o, x, and X */ if (!PyLong_Check(v)) { if (type == 'o' || type == 'x' || type == 'X') { - iobj = PyNumber_Index(v); - if (iobj == NULL) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - goto wrongtype; - return -1; - } + iobj = _PyNumber_Index(v); } else { iobj = PyNumber_Long(v); - if (iobj == NULL ) { - if (PyErr_ExceptionMatches(PyExc_TypeError)) - goto wrongtype; - return -1; - } + } + if (iobj == NULL ) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) + goto wrongtype; + return -1; } assert(PyLong_Check(iobj)); } @@ -14808,7 +14967,7 @@ wrongtype: break; default: PyErr_Format(PyExc_TypeError, - "%%%c format: a number is required, " + "%%%c format: a real number is required, " "not %.200s", type, Py_TYPE(v)->tp_name); break; @@ -14827,24 +14986,17 @@ formatchar(PyObject *v) goto onError; } else { - PyObject *iobj; - long x; - /* make sure number is a type of integer */ - if (!PyLong_Check(v)) { - iobj = PyNumber_Index(v); - if (iobj == NULL) { + int overflow; + long x = PyLong_AsLongAndOverflow(v, &overflow); + if (x == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches(PyExc_TypeError)) { goto onError; } - x = PyLong_AsLong(iobj); - Py_DECREF(iobj); - } - else { - x = PyLong_AsLong(v); + return (Py_UCS4) -1; } - if (x == -1 && PyErr_Occurred()) - goto onError; if (x < 0 || x > MAX_UNICODE) { + /* this includes an overflow in converting to C long */ PyErr_SetString(PyExc_OverflowError, "%c arg not in range(0x110000)"); return (Py_UCS4) -1; @@ -15442,52 +15594,57 @@ PyUnicode_Format(PyObject *format, PyObject *args) } static PyObject * -unicode_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); +unicode_subtype_new(PyTypeObject *type, PyObject *unicode); + +/*[clinic input] +@classmethod +str.__new__ as unicode_new + + object as x: object = NULL + encoding: str = NULL + errors: str = NULL + +[clinic start generated code]*/ static PyObject * -unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +unicode_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, + const char *errors) +/*[clinic end generated code: output=fc72d4878b0b57e9 input=e81255e5676d174e]*/ { - PyObject *x = NULL; - static char *kwlist[] = {"object", "encoding", "errors", 0}; - char *encoding = NULL; - char *errors = NULL; + PyObject *unicode; + if (x == NULL) { + unicode = unicode_new_empty(); + } + else if (encoding == NULL && errors == NULL) { + unicode = PyObject_Str(x); + } + else { + unicode = PyUnicode_FromEncodedObject(x, encoding, errors); + } - if (type != &PyUnicode_Type) - return unicode_subtype_new(type, args, kwds); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:str", - kwlist, &x, &encoding, &errors)) - return NULL; - if (x == NULL) - _Py_RETURN_UNICODE_EMPTY(); - if (encoding == NULL && errors == NULL) - return PyObject_Str(x); - else - return PyUnicode_FromEncodedObject(x, encoding, errors); + if (unicode != NULL && type != &PyUnicode_Type) { + Py_SETREF(unicode, unicode_subtype_new(type, unicode)); + } + return unicode; } static PyObject * -unicode_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +unicode_subtype_new(PyTypeObject *type, PyObject *unicode) { - PyObject *unicode, *self; + PyObject *self; Py_ssize_t length, char_size; int share_wstr, share_utf8; unsigned int kind; void *data; assert(PyType_IsSubtype(type, &PyUnicode_Type)); - - unicode = unicode_new(&PyUnicode_Type, args, kwds); - if (unicode == NULL) - return NULL; assert(_PyUnicode_CHECK(unicode)); if (PyUnicode_READY(unicode) == -1) { - Py_DECREF(unicode); return NULL; } self = type->tp_alloc(type, 0); if (self == NULL) { - Py_DECREF(unicode); return NULL; } kind = PyUnicode_KIND(unicode); @@ -15534,7 +15691,7 @@ unicode_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyErr_NoMemory(); goto onError; } - data = PyObject_MALLOC((length + 1) * char_size); + data = PyObject_Malloc((length + 1) * char_size); if (data == NULL) { PyErr_NoMemory(); goto onError; @@ -15556,11 +15713,9 @@ unicode_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) #ifdef Py_DEBUG _PyUnicode_HASH(self) = _PyUnicode_HASH(unicode); #endif - Py_DECREF(unicode); return self; onError: - Py_DECREF(unicode); Py_DECREF(self); return NULL; } @@ -15601,7 +15756,8 @@ PyTypeObject PyUnicode_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | - Py_TPFLAGS_UNICODE_SUBCLASS, /* tp_flags */ + Py_TPFLAGS_UNICODE_SUBCLASS | + _Py_TPFLAGS_MATCH_SELF, /* tp_flags */ unicode_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ @@ -15626,36 +15782,40 @@ PyTypeObject PyUnicode_Type = { /* Initialize the Unicode implementation */ PyStatus -_PyUnicode_Init(void) -{ - /* XXX - move this array to unicodectype.c ? */ - Py_UCS2 linebreak[] = { - 0x000A, /* LINE FEED */ - 0x000D, /* CARRIAGE RETURN */ - 0x001C, /* FILE SEPARATOR */ - 0x001D, /* GROUP SEPARATOR */ - 0x001E, /* RECORD SEPARATOR */ - 0x0085, /* NEXT LINE */ - 0x2028, /* LINE SEPARATOR */ - 0x2029, /* PARAGRAPH SEPARATOR */ - }; - - /* Init the implementation */ - _Py_INCREF_UNICODE_EMPTY(); - if (!unicode_empty) { - return _PyStatus_ERR("Can't create empty string"); - } - Py_DECREF(unicode_empty); +_PyUnicode_Init(PyInterpreterState *interp) +{ + struct _Py_unicode_state *state = &interp->unicode; + if (unicode_create_empty_string_singleton(state) < 0) { + return _PyStatus_NO_MEMORY(); + } + + if (_Py_IsMainInterpreter(interp)) { + /* initialize the linebreak bloom filter */ + const Py_UCS2 linebreak[] = { + 0x000A, /* LINE FEED */ + 0x000D, /* CARRIAGE RETURN */ + 0x001C, /* FILE SEPARATOR */ + 0x001D, /* GROUP SEPARATOR */ + 0x001E, /* RECORD SEPARATOR */ + 0x0085, /* NEXT LINE */ + 0x2028, /* LINE SEPARATOR */ + 0x2029, /* PARAGRAPH SEPARATOR */ + }; + bloom_linebreak = make_bloom_mask( + PyUnicode_2BYTE_KIND, linebreak, + Py_ARRAY_LENGTH(linebreak)); + } + + return _PyStatus_OK(); +} + +PyStatus +_PyUnicode_InitTypes(void) +{ if (PyType_Ready(&PyUnicode_Type) < 0) { return _PyStatus_ERR("Can't initialize unicode type"); } - - /* initialize the linebreak bloom filter */ - bloom_linebreak = make_bloom_mask( - PyUnicode_2BYTE_KIND, linebreak, - Py_ARRAY_LENGTH(linebreak)); - if (PyType_Ready(&EncodingMapType) < 0) { return _PyStatus_ERR("Can't initialize encoding map type"); } @@ -15693,6 +15853,11 @@ PyUnicode_InternInPlace(PyObject **p) } #ifdef INTERNED_STRINGS + if (PyUnicode_READY(s) == -1) { + PyErr_Clear(); + return; + } + if (interned == NULL) { interned = PyDict_New(); if (interned == NULL) { @@ -15701,9 +15866,7 @@ PyUnicode_InternInPlace(PyObject **p) } } - PyObject *t; - t = PyDict_SetDefault(interned, s, s); - + PyObject *t = PyDict_SetDefault(interned, s, s); if (t == NULL) { PyErr_Clear(); return; @@ -15715,16 +15878,30 @@ PyUnicode_InternInPlace(PyObject **p) return; } - /* The two references in interned are not counted by refcnt. - The deallocator will take care of this */ + /* The two references in interned dict (key and value) are not counted by + refcnt. unicode_dealloc() and _PyUnicode_ClearInterned() take care of + this. */ Py_SET_REFCNT(s, Py_REFCNT(s) - 2); _PyUnicode_STATE(s).interned = SSTATE_INTERNED_MORTAL; +#else + // PyDict expects that interned strings have their hash + // (PyASCIIObject.hash) already computed. + (void)unicode_hash(s); #endif } void PyUnicode_InternImmortal(PyObject **p) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "PyUnicode_InternImmortal() is deprecated; " + "use PyUnicode_InternInPlace() instead", 1) < 0) + { + // The function has no return value, the exception cannot + // be reported to the caller, so just log it. + PyErr_WriteUnraisable(NULL); + } + PyUnicode_InternInPlace(p); if (PyUnicode_CHECK_INTERNED(*p) != SSTATE_INTERNED_IMMORTAL) { _PyUnicode_STATE(*p).interned = SSTATE_INTERNED_IMMORTAL; @@ -15743,45 +15920,45 @@ PyUnicode_InternFromString(const char *cp) } -#if defined(WITH_VALGRIND) || defined(__INSURE__) -static void -unicode_release_interned(void) +void +_PyUnicode_ClearInterned(PyInterpreterState *interp) { - if (interned == NULL || !PyDict_Check(interned)) { + if (!_Py_IsMainInterpreter(interp)) { + // interned dict is shared by all interpreters return; } - PyObject *keys = PyDict_Keys(interned); - if (keys == NULL || !PyList_Check(keys)) { - PyErr_Clear(); + + if (interned == NULL) { return; } + assert(PyDict_CheckExact(interned)); - /* Since unicode_release_interned() is intended to help a leak - detector, interned unicode strings are not forcibly deallocated; - rather, we give them their stolen references back, and then clear - and DECREF the interned dict. */ + /* Interned unicode strings are not forcibly deallocated; rather, we give + them their stolen references back, and then clear and DECREF the + interned dict. */ - Py_ssize_t n = PyList_GET_SIZE(keys); #ifdef INTERNED_STATS - fprintf(stderr, "releasing %" PY_FORMAT_SIZE_T "d interned strings\n", - n); + fprintf(stderr, "releasing %zd interned strings\n", + PyDict_GET_SIZE(interned)); Py_ssize_t immortal_size = 0, mortal_size = 0; #endif - for (Py_ssize_t i = 0; i < n; i++) { - PyObject *s = PyList_GET_ITEM(keys, i); - if (PyUnicode_READY(s) == -1) { - Py_UNREACHABLE(); - } + Py_ssize_t pos = 0; + PyObject *s, *ignored_value; + while (PyDict_Next(interned, &pos, &s, &ignored_value)) { + assert(PyUnicode_IS_READY(s)); + switch (PyUnicode_CHECK_INTERNED(s)) { case SSTATE_INTERNED_IMMORTAL: - Py_REFCNT(s) += 1; + Py_SET_REFCNT(s, Py_REFCNT(s) + 1); #ifdef INTERNED_STATS immortal_size += PyUnicode_GET_LENGTH(s); #endif break; case SSTATE_INTERNED_MORTAL: - Py_REFCNT(s) += 2; + // Restore the two references (key and value) ignored + // by PyUnicode_InternInPlace(). + Py_SET_REFCNT(s, Py_REFCNT(s) + 2); #ifdef INTERNED_STATS mortal_size += PyUnicode_GET_LENGTH(s); #endif @@ -15794,15 +15971,14 @@ unicode_release_interned(void) _PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED; } #ifdef INTERNED_STATS - fprintf(stderr, "total size of all interned strings: " - "%" PY_FORMAT_SIZE_T "d/%" PY_FORMAT_SIZE_T "d " - "mortal/immortal\n", mortal_size, immortal_size); + fprintf(stderr, + "total size of all interned strings: %zd/%zd mortal/immortal\n", + mortal_size, immortal_size); #endif - Py_DECREF(keys); + PyDict_Clear(interned); Py_CLEAR(interned); } -#endif /********************* Unicode Iterator **************************/ @@ -15964,127 +16140,6 @@ unicode_iter(PyObject *seq) return (PyObject *)it; } - -size_t -Py_UNICODE_strlen(const Py_UNICODE *u) -{ - return wcslen(u); -} - -Py_UNICODE* -Py_UNICODE_strcpy(Py_UNICODE *s1, const Py_UNICODE *s2) -{ - Py_UNICODE *u = s1; - while ((*u++ = *s2++)); - return s1; -} - -Py_UNICODE* -Py_UNICODE_strncpy(Py_UNICODE *s1, const Py_UNICODE *s2, size_t n) -{ - Py_UNICODE *u = s1; - while ((*u++ = *s2++)) - if (n-- == 0) - break; - return s1; -} - -Py_UNICODE* -Py_UNICODE_strcat(Py_UNICODE *s1, const Py_UNICODE *s2) -{ - Py_UNICODE *u1 = s1; - u1 += wcslen(u1); - while ((*u1++ = *s2++)); - return s1; -} - -int -Py_UNICODE_strcmp(const Py_UNICODE *s1, const Py_UNICODE *s2) -{ - while (*s1 && *s2 && *s1 == *s2) - s1++, s2++; - if (*s1 && *s2) - return (*s1 < *s2) ? -1 : +1; - if (*s1) - return 1; - if (*s2) - return -1; - return 0; -} - -int -Py_UNICODE_strncmp(const Py_UNICODE *s1, const Py_UNICODE *s2, size_t n) -{ - Py_UNICODE u1, u2; - for (; n != 0; n--) { - u1 = *s1; - u2 = *s2; - if (u1 != u2) - return (u1 < u2) ? -1 : +1; - if (u1 == '\0') - return 0; - s1++; - s2++; - } - return 0; -} - -Py_UNICODE* -Py_UNICODE_strchr(const Py_UNICODE *s, Py_UNICODE c) -{ - const Py_UNICODE *p; - for (p = s; *p; p++) - if (*p == c) - return (Py_UNICODE*)p; - return NULL; -} - -Py_UNICODE* -Py_UNICODE_strrchr(const Py_UNICODE *s, Py_UNICODE c) -{ - const Py_UNICODE *p; - p = s + wcslen(s); - while (p != s) { - p--; - if (*p == c) - return (Py_UNICODE*)p; - } - return NULL; -} - -Py_UNICODE* -PyUnicode_AsUnicodeCopy(PyObject *unicode) -{ - Py_UNICODE *u, *copy; - Py_ssize_t len, size; - - if (!PyUnicode_Check(unicode)) { - PyErr_BadArgument(); - return NULL; - } -_Py_COMP_DIAG_PUSH -_Py_COMP_DIAG_IGNORE_DEPR_DECLS - u = PyUnicode_AsUnicodeAndSize(unicode, &len); -_Py_COMP_DIAG_POP - if (u == NULL) - return NULL; - /* Ensure we won't overflow the size. */ - if (len > ((PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(Py_UNICODE)) - 1)) { - PyErr_NoMemory(); - return NULL; - } - size = len + 1; /* copy the null character */ - size *= sizeof(Py_UNICODE); - copy = PyMem_Malloc(size); - if (copy == NULL) { - PyErr_NoMemory(); - return NULL; - } - memcpy(copy, u, size); - return copy; -} - - static int encode_wstr_utf8(wchar_t *wstr, char **str, const char *name) { @@ -16150,10 +16205,10 @@ error: static PyStatus -init_stdio_encoding(PyThreadState *tstate) +init_stdio_encoding(PyInterpreterState *interp) { /* Update the stdio encoding to the normalized Python codec name. */ - PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(tstate->interp); + PyConfig *config = (PyConfig*)_PyInterpreterState_GetConfig(interp); if (config_get_codec_name(&config->stdio_encoding) < 0) { return _PyStatus_ERR("failed to get the Python codec name " "of the stdio encoding"); @@ -16246,7 +16301,7 @@ _PyUnicode_InitEncodings(PyThreadState *tstate) return status; } - return init_stdio_encoding(tstate); + return init_stdio_encoding(tstate->interp); } @@ -16290,33 +16345,23 @@ _PyUnicode_EnableLegacyWindowsFSEncoding(void) void -_PyUnicode_Fini(PyThreadState *tstate) -{ - if (_Py_IsMainInterpreter(tstate)) { -#if defined(WITH_VALGRIND) || defined(__INSURE__) - /* Insure++ is a memory analysis tool that aids in discovering - * memory leaks and other memory problems. On Python exit, the - * interned string dictionaries are flagged as being in use at exit - * (which it is). Under normal circumstances, this is fine because - * the memory will be automatically reclaimed by the system. Under - * memory debugging, it's a huge source of useless noise, so we - * trade off slower shutdown for less distraction in the memory - * reports. -baw - */ - unicode_release_interned(); -#endif /* __INSURE__ */ - - Py_CLEAR(unicode_empty); - -#ifdef LATIN1_SINGLETONS - for (Py_ssize_t i = 0; i < 256; i++) { - Py_CLEAR(unicode_latin1[i]); - } -#endif - unicode_clear_static_strings(); +_PyUnicode_Fini(PyInterpreterState *interp) +{ + struct _Py_unicode_state *state = &interp->unicode; + + if (_Py_IsMainInterpreter(interp)) { + // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini() + assert(interned == NULL); } - _PyUnicode_FiniEncodings(&tstate->interp->unicode.fs_codec); + _PyUnicode_FiniEncodings(&state->fs_codec); + + unicode_clear_identifiers(state); + + for (Py_ssize_t i = 0; i < 256; i++) { + Py_CLEAR(state->latin1[i]); + } + Py_CLEAR(state->empty_string); } @@ -16333,20 +16378,16 @@ static PyMethodDef _string_methods[] = { static struct PyModuleDef _string_module = { PyModuleDef_HEAD_INIT, - "_string", - PyDoc_STR("string helper module"), - 0, - _string_methods, - NULL, - NULL, - NULL, - NULL + .m_name = "_string", + .m_doc = PyDoc_STR("string helper module"), + .m_size = 0, + .m_methods = _string_methods, }; PyMODINIT_FUNC PyInit__string(void) { - return PyModule_Create(&_string_module); + return PyModuleDef_Init(&_string_module); } diff --git a/contrib/tools/python3/src/Objects/unionobject.c b/contrib/tools/python3/src/Objects/unionobject.c new file mode 100644 index 0000000000..80c70389ab --- /dev/null +++ b/contrib/tools/python3/src/Objects/unionobject.c @@ -0,0 +1,496 @@ +// types.UnionType -- used to represent e.g. Union[int, str], int | str +#include "Python.h" +#include "pycore_object.h" // _PyObject_GC_TRACK/UNTRACK +#include "pycore_unionobject.h" +#include "structmember.h" + + +static PyObject *make_union(PyObject *); + + +typedef struct { + PyObject_HEAD + PyObject *args; + PyObject *parameters; +} unionobject; + +static void +unionobject_dealloc(PyObject *self) +{ + unionobject *alias = (unionobject *)self; + + _PyObject_GC_UNTRACK(self); + + Py_XDECREF(alias->args); + Py_XDECREF(alias->parameters); + Py_TYPE(self)->tp_free(self); +} + +static int +union_traverse(PyObject *self, visitproc visit, void *arg) +{ + unionobject *alias = (unionobject *)self; + Py_VISIT(alias->args); + Py_VISIT(alias->parameters); + return 0; +} + +static Py_hash_t +union_hash(PyObject *self) +{ + unionobject *alias = (unionobject *)self; + PyObject *args = PyFrozenSet_New(alias->args); + if (args == NULL) { + return (Py_hash_t)-1; + } + Py_hash_t hash = PyObject_Hash(args); + Py_DECREF(args); + return hash; +} + +static int +is_generic_alias_in_args(PyObject *args) +{ + Py_ssize_t nargs = PyTuple_GET_SIZE(args); + for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { + PyObject *arg = PyTuple_GET_ITEM(args, iarg); + if (_PyGenericAlias_Check(arg)) { + return 0; + } + } + return 1; +} + +static PyObject * +union_instancecheck(PyObject *self, PyObject *instance) +{ + unionobject *alias = (unionobject *) self; + Py_ssize_t nargs = PyTuple_GET_SIZE(alias->args); + if (!is_generic_alias_in_args(alias->args)) { + PyErr_SetString(PyExc_TypeError, + "isinstance() argument 2 cannot contain a parameterized generic"); + return NULL; + } + for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { + PyObject *arg = PyTuple_GET_ITEM(alias->args, iarg); + if (PyType_Check(arg)) { + int res = PyObject_IsInstance(instance, arg); + if (res < 0) { + return NULL; + } + if (res) { + Py_RETURN_TRUE; + } + } + } + Py_RETURN_FALSE; +} + +static PyObject * +union_subclasscheck(PyObject *self, PyObject *instance) +{ + if (!PyType_Check(instance)) { + PyErr_SetString(PyExc_TypeError, "issubclass() arg 1 must be a class"); + return NULL; + } + unionobject *alias = (unionobject *)self; + if (!is_generic_alias_in_args(alias->args)) { + PyErr_SetString(PyExc_TypeError, + "issubclass() argument 2 cannot contain a parameterized generic"); + return NULL; + } + Py_ssize_t nargs = PyTuple_GET_SIZE(alias->args); + for (Py_ssize_t iarg = 0; iarg < nargs; iarg++) { + PyObject *arg = PyTuple_GET_ITEM(alias->args, iarg); + if (PyType_Check(arg)) { + int res = PyObject_IsSubclass(instance, arg); + if (res < 0) { + return NULL; + } + if (res) { + Py_RETURN_TRUE; + } + } + } + Py_RETURN_FALSE; +} + +static PyObject * +union_richcompare(PyObject *a, PyObject *b, int op) +{ + if (!_PyUnion_Check(b) || (op != Py_EQ && op != Py_NE)) { + Py_RETURN_NOTIMPLEMENTED; + } + + PyObject *a_set = PySet_New(((unionobject*)a)->args); + if (a_set == NULL) { + return NULL; + } + PyObject *b_set = PySet_New(((unionobject*)b)->args); + if (b_set == NULL) { + Py_DECREF(a_set); + return NULL; + } + PyObject *result = PyObject_RichCompare(a_set, b_set, op); + Py_DECREF(b_set); + Py_DECREF(a_set); + return result; +} + +static PyObject* +flatten_args(PyObject* args) +{ + Py_ssize_t arg_length = PyTuple_GET_SIZE(args); + Py_ssize_t total_args = 0; + // Get number of total args once it's flattened. + for (Py_ssize_t i = 0; i < arg_length; i++) { + PyObject *arg = PyTuple_GET_ITEM(args, i); + if (_PyUnion_Check(arg)) { + total_args += PyTuple_GET_SIZE(((unionobject*) arg)->args); + } else { + total_args++; + } + } + // Create new tuple of flattened args. + PyObject *flattened_args = PyTuple_New(total_args); + if (flattened_args == NULL) { + return NULL; + } + Py_ssize_t pos = 0; + for (Py_ssize_t i = 0; i < arg_length; i++) { + PyObject *arg = PyTuple_GET_ITEM(args, i); + if (_PyUnion_Check(arg)) { + PyObject* nested_args = ((unionobject*)arg)->args; + Py_ssize_t nested_arg_length = PyTuple_GET_SIZE(nested_args); + for (Py_ssize_t j = 0; j < nested_arg_length; j++) { + PyObject* nested_arg = PyTuple_GET_ITEM(nested_args, j); + Py_INCREF(nested_arg); + PyTuple_SET_ITEM(flattened_args, pos, nested_arg); + pos++; + } + } else { + if (arg == Py_None) { + arg = (PyObject *)&_PyNone_Type; + } + Py_INCREF(arg); + PyTuple_SET_ITEM(flattened_args, pos, arg); + pos++; + } + } + assert(pos == total_args); + return flattened_args; +} + +static PyObject* +dedup_and_flatten_args(PyObject* args) +{ + args = flatten_args(args); + if (args == NULL) { + return NULL; + } + Py_ssize_t arg_length = PyTuple_GET_SIZE(args); + PyObject *new_args = PyTuple_New(arg_length); + if (new_args == NULL) { + Py_DECREF(args); + return NULL; + } + // Add unique elements to an array. + Py_ssize_t added_items = 0; + for (Py_ssize_t i = 0; i < arg_length; i++) { + int is_duplicate = 0; + PyObject* i_element = PyTuple_GET_ITEM(args, i); + for (Py_ssize_t j = 0; j < added_items; j++) { + PyObject* j_element = PyTuple_GET_ITEM(new_args, j); + int is_ga = _PyGenericAlias_Check(i_element) && + _PyGenericAlias_Check(j_element); + // RichCompare to also deduplicate GenericAlias types (slower) + is_duplicate = is_ga ? PyObject_RichCompareBool(i_element, j_element, Py_EQ) + : i_element == j_element; + // Should only happen if RichCompare fails + if (is_duplicate < 0) { + Py_DECREF(args); + Py_DECREF(new_args); + return NULL; + } + if (is_duplicate) + break; + } + if (!is_duplicate) { + Py_INCREF(i_element); + PyTuple_SET_ITEM(new_args, added_items, i_element); + added_items++; + } + } + Py_DECREF(args); + _PyTuple_Resize(&new_args, added_items); + return new_args; +} + +static int +is_unionable(PyObject *obj) +{ + return (obj == Py_None || + PyType_Check(obj) || + _PyGenericAlias_Check(obj) || + _PyUnion_Check(obj)); +} + +PyObject * +_Py_union_type_or(PyObject* self, PyObject* other) +{ + if (!is_unionable(self) || !is_unionable(other)) { + Py_RETURN_NOTIMPLEMENTED; + } + + PyObject *tuple = PyTuple_Pack(2, self, other); + if (tuple == NULL) { + return NULL; + } + + PyObject *new_union = make_union(tuple); + Py_DECREF(tuple); + return new_union; +} + +static int +union_repr_item(_PyUnicodeWriter *writer, PyObject *p) +{ + _Py_IDENTIFIER(__module__); + _Py_IDENTIFIER(__qualname__); + _Py_IDENTIFIER(__origin__); + _Py_IDENTIFIER(__args__); + PyObject *qualname = NULL; + PyObject *module = NULL; + PyObject *tmp; + PyObject *r = NULL; + int err; + + if (p == (PyObject *)&_PyNone_Type) { + return _PyUnicodeWriter_WriteASCIIString(writer, "None", 4); + } + + if (_PyObject_LookupAttrId(p, &PyId___origin__, &tmp) < 0) { + goto exit; + } + + if (tmp) { + Py_DECREF(tmp); + if (_PyObject_LookupAttrId(p, &PyId___args__, &tmp) < 0) { + goto exit; + } + if (tmp) { + // It looks like a GenericAlias + Py_DECREF(tmp); + goto use_repr; + } + } + + if (_PyObject_LookupAttrId(p, &PyId___qualname__, &qualname) < 0) { + goto exit; + } + if (qualname == NULL) { + goto use_repr; + } + if (_PyObject_LookupAttrId(p, &PyId___module__, &module) < 0) { + goto exit; + } + if (module == NULL || module == Py_None) { + goto use_repr; + } + + // Looks like a class + if (PyUnicode_Check(module) && + _PyUnicode_EqualToASCIIString(module, "builtins")) + { + // builtins don't need a module name + r = PyObject_Str(qualname); + goto exit; + } + else { + r = PyUnicode_FromFormat("%S.%S", module, qualname); + goto exit; + } + +use_repr: + r = PyObject_Repr(p); +exit: + Py_XDECREF(qualname); + Py_XDECREF(module); + if (r == NULL) { + return -1; + } + err = _PyUnicodeWriter_WriteStr(writer, r); + Py_DECREF(r); + return err; +} + +static PyObject * +union_repr(PyObject *self) +{ + unionobject *alias = (unionobject *)self; + Py_ssize_t len = PyTuple_GET_SIZE(alias->args); + + _PyUnicodeWriter writer; + _PyUnicodeWriter_Init(&writer); + for (Py_ssize_t i = 0; i < len; i++) { + if (i > 0 && _PyUnicodeWriter_WriteASCIIString(&writer, " | ", 3) < 0) { + goto error; + } + PyObject *p = PyTuple_GET_ITEM(alias->args, i); + if (union_repr_item(&writer, p) < 0) { + goto error; + } + } + return _PyUnicodeWriter_Finish(&writer); +error: + _PyUnicodeWriter_Dealloc(&writer); + return NULL; +} + +static PyMemberDef union_members[] = { + {"__args__", T_OBJECT, offsetof(unionobject, args), READONLY}, + {0} +}; + +static PyMethodDef union_methods[] = { + {"__instancecheck__", union_instancecheck, METH_O}, + {"__subclasscheck__", union_subclasscheck, METH_O}, + {0}}; + + +static PyObject * +union_getitem(PyObject *self, PyObject *item) +{ + unionobject *alias = (unionobject *)self; + // Populate __parameters__ if needed. + if (alias->parameters == NULL) { + alias->parameters = _Py_make_parameters(alias->args); + if (alias->parameters == NULL) { + return NULL; + } + } + + PyObject *newargs = _Py_subs_parameters(self, alias->args, alias->parameters, item); + if (newargs == NULL) { + return NULL; + } + + PyObject *res; + Py_ssize_t nargs = PyTuple_GET_SIZE(newargs); + if (nargs == 0) { + res = make_union(newargs); + } + else { + res = PyTuple_GET_ITEM(newargs, 0); + Py_INCREF(res); + for (Py_ssize_t iarg = 1; iarg < nargs; iarg++) { + PyObject *arg = PyTuple_GET_ITEM(newargs, iarg); + Py_SETREF(res, PyNumber_Or(res, arg)); + if (res == NULL) { + break; + } + } + } + Py_DECREF(newargs); + return res; +} + +static PyMappingMethods union_as_mapping = { + .mp_subscript = union_getitem, +}; + +static PyObject * +union_parameters(PyObject *self, void *Py_UNUSED(unused)) +{ + unionobject *alias = (unionobject *)self; + if (alias->parameters == NULL) { + alias->parameters = _Py_make_parameters(alias->args); + if (alias->parameters == NULL) { + return NULL; + } + } + Py_INCREF(alias->parameters); + return alias->parameters; +} + +static PyGetSetDef union_properties[] = { + {"__parameters__", union_parameters, (setter)NULL, "Type variables in the types.UnionType.", NULL}, + {0} +}; + +static PyNumberMethods union_as_number = { + .nb_or = _Py_union_type_or, // Add __or__ function +}; + +static const char* const cls_attrs[] = { + "__module__", // Required for compatibility with typing module + NULL, +}; + +static PyObject * +union_getattro(PyObject *self, PyObject *name) +{ + unionobject *alias = (unionobject *)self; + if (PyUnicode_Check(name)) { + for (const char * const *p = cls_attrs; ; p++) { + if (*p == NULL) { + break; + } + if (_PyUnicode_EqualToASCIIString(name, *p)) { + return PyObject_GetAttr((PyObject *) Py_TYPE(alias), name); + } + } + } + return PyObject_GenericGetAttr(self, name); +} + +PyTypeObject _PyUnion_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + .tp_name = "types.UnionType", + .tp_doc = "Represent a PEP 604 union type\n" + "\n" + "E.g. for int | str", + .tp_basicsize = sizeof(unionobject), + .tp_dealloc = unionobject_dealloc, + .tp_alloc = PyType_GenericAlloc, + .tp_free = PyObject_GC_Del, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + .tp_traverse = union_traverse, + .tp_hash = union_hash, + .tp_getattro = union_getattro, + .tp_members = union_members, + .tp_methods = union_methods, + .tp_richcompare = union_richcompare, + .tp_as_mapping = &union_as_mapping, + .tp_as_number = &union_as_number, + .tp_repr = union_repr, + .tp_getset = union_properties, +}; + +static PyObject * +make_union(PyObject *args) +{ + assert(PyTuple_CheckExact(args)); + + args = dedup_and_flatten_args(args); + if (args == NULL) { + return NULL; + } + if (PyTuple_GET_SIZE(args) == 1) { + PyObject *result1 = PyTuple_GET_ITEM(args, 0); + Py_INCREF(result1); + Py_DECREF(args); + return result1; + } + + unionobject *result = PyObject_GC_New(unionobject, &_PyUnion_Type); + if (result == NULL) { + Py_DECREF(args); + return NULL; + } + + result->parameters = NULL; + result->args = args; + _PyObject_GC_TRACK(result); + return (PyObject*)result; +} |