aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Objects
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-04-18 12:39:32 +0300
committershadchin <shadchin@yandex-team.ru>2022-04-18 12:39:32 +0300
commitd4be68e361f4258cf0848fc70018dfe37a2acc24 (patch)
tree153e294cd97ac8b5d7a989612704a0c1f58e8ad4 /contrib/tools/python3/src/Objects
parent260c02f5ccf242d9d9b8a873afaf6588c00237d6 (diff)
downloadydb-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')
-rw-r--r--contrib/tools/python3/src/Objects/abstract.c735
-rw-r--r--contrib/tools/python3/src/Objects/boolobject.c25
-rw-r--r--contrib/tools/python3/src/Objects/bytearrayobject.c95
-rw-r--r--contrib/tools/python3/src/Objects/bytes_methods.c21
-rw-r--r--contrib/tools/python3/src/Objects/bytesobject.c379
-rw-r--r--contrib/tools/python3/src/Objects/call.c144
-rw-r--r--contrib/tools/python3/src/Objects/capsule.c6
-rw-r--r--contrib/tools/python3/src/Objects/clinic/bytearrayobject.c.h123
-rw-r--r--contrib/tools/python3/src/Objects/clinic/bytesobject.c.h104
-rw-r--r--contrib/tools/python3/src/Objects/clinic/codeobject.c.h187
-rw-r--r--contrib/tools/python3/src/Objects/clinic/complexobject.c.h71
-rw-r--r--contrib/tools/python3/src/Objects/clinic/dictobject.c.h5
-rw-r--r--contrib/tools/python3/src/Objects/clinic/floatobject.c.h4
-rw-r--r--contrib/tools/python3/src/Objects/clinic/listobject.c.h21
-rw-r--r--contrib/tools/python3/src/Objects/clinic/longobject.c.h68
-rw-r--r--contrib/tools/python3/src/Objects/clinic/memoryobject.c.h199
-rw-r--r--contrib/tools/python3/src/Objects/clinic/odictobject.c.h45
-rw-r--r--contrib/tools/python3/src/Objects/clinic/typeobject.c.h7
-rw-r--r--contrib/tools/python3/src/Objects/clinic/unicodeobject.c.h130
-rw-r--r--contrib/tools/python3/src/Objects/codeobject.c485
-rw-r--r--contrib/tools/python3/src/Objects/complexobject.c135
-rw-r--r--contrib/tools/python3/src/Objects/descrobject.c82
-rw-r--r--contrib/tools/python3/src/Objects/dictobject.c587
-rw-r--r--contrib/tools/python3/src/Objects/enumobject.c22
-rw-r--r--contrib/tools/python3/src/Objects/exceptions.c463
-rw-r--r--contrib/tools/python3/src/Objects/fileobject.c42
-rw-r--r--contrib/tools/python3/src/Objects/floatobject.c153
-rw-r--r--contrib/tools/python3/src/Objects/frameobject.c435
-rw-r--r--contrib/tools/python3/src/Objects/funcobject.c249
-rw-r--r--contrib/tools/python3/src/Objects/genericaliasobject.c61
-rw-r--r--contrib/tools/python3/src/Objects/genobject.c393
-rw-r--r--contrib/tools/python3/src/Objects/interpreteridobject.c12
-rw-r--r--contrib/tools/python3/src/Objects/iterobject.c215
-rw-r--r--contrib/tools/python3/src/Objects/listobject.c125
-rw-r--r--contrib/tools/python3/src/Objects/longobject.c365
-rw-r--r--contrib/tools/python3/src/Objects/memoryobject.c270
-rw-r--r--contrib/tools/python3/src/Objects/moduleobject.c153
-rw-r--r--contrib/tools/python3/src/Objects/object.c354
-rw-r--r--contrib/tools/python3/src/Objects/obmalloc.c365
-rw-r--r--contrib/tools/python3/src/Objects/odictobject.c49
-rw-r--r--contrib/tools/python3/src/Objects/rangeobject.c91
-rw-r--r--contrib/tools/python3/src/Objects/setobject.c68
-rw-r--r--contrib/tools/python3/src/Objects/sliceobject.c57
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/asciilib.h1
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/clinic/transmogrify.h.h35
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/codecs.h39
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/fastsearch.h490
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/find_max_char.h22
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/join.h2
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/partition.h27
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/stringdefs.h1
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/ucs1lib.h1
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/ucs2lib.h1
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/ucs4lib.h1
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/unicode_format.h4
-rw-r--r--contrib/tools/python3/src/Objects/stringlib/unicodedefs.h1
-rw-r--r--contrib/tools/python3/src/Objects/structseq.c163
-rw-r--r--contrib/tools/python3/src/Objects/tupleobject.c210
-rw-r--r--contrib/tools/python3/src/Objects/typeobject.c2416
-rw-r--r--contrib/tools/python3/src/Objects/typeslots.inc161
-rw-r--r--contrib/tools/python3/src/Objects/unicodeobject.c1127
-rw-r--r--contrib/tools/python3/src/Objects/unionobject.c496
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;
+}