From bc42a04940bb16a837421bf313c8126b4d8fc3b3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 13 Sep 2016 09:38:29 +0200 Subject: Issue #28040: Cleanup find_empty_slot() find_empty_slot() only supports combined dict --- Objects/dictobject.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 8b88ec6eef..bb5962a1a5 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -987,7 +987,7 @@ _PyDict_MaybeUntrack(PyObject *op) when it is known that the key is not present in the dict. The dict must be combined. */ -static Py_ssize_t +static void find_empty_slot(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { @@ -1011,11 +1011,7 @@ find_empty_slot(PyDictObject *mp, PyObject *key, Py_hash_t hash, ep = &ep0[mp->ma_keys->dk_nentries]; *hashpos = i & mask; assert(ep->me_value == NULL); - if (mp->ma_values) - *value_addr = &mp->ma_values[ix]; - else - *value_addr = &ep->me_value; - return ix; + *value_addr = &ep->me_value; } static int -- cgit v1.2.1 From e7c175efdafc8a76621c7331d4cfae9654ebea5b Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sat, 17 Sep 2016 17:50:50 +0100 Subject: Issue #27222: various cleanups in long_rshift. Thanks Oren Milman. --- Objects/longobject.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'Objects') diff --git a/Objects/longobject.c b/Objects/longobject.c index a453241b3f..0822f9bcb3 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -4296,22 +4296,22 @@ long_rshift(PyLongObject *a, PyLongObject *b) PyLongObject *a1, *a2; a1 = (PyLongObject *) long_invert(a); if (a1 == NULL) - goto rshift_error; + return NULL; a2 = (PyLongObject *) long_rshift(a1, b); Py_DECREF(a1); if (a2 == NULL) - goto rshift_error; + return NULL; z = (PyLongObject *) long_invert(a2); Py_DECREF(a2); } else { shiftby = PyLong_AsSsize_t((PyObject *)b); if (shiftby == -1L && PyErr_Occurred()) - goto rshift_error; + return NULL; if (shiftby < 0) { PyErr_SetString(PyExc_ValueError, "negative shift count"); - goto rshift_error; + return NULL; } wordshift = shiftby / PyLong_SHIFT; newsize = Py_ABS(Py_SIZE(a)) - wordshift; @@ -4323,19 +4323,15 @@ long_rshift(PyLongObject *a, PyLongObject *b) himask = PyLong_MASK ^ lomask; z = _PyLong_New(newsize); if (z == NULL) - goto rshift_error; - if (Py_SIZE(a) < 0) - Py_SIZE(z) = -(Py_SIZE(z)); + return NULL; for (i = 0, j = wordshift; i < newsize; i++, j++) { z->ob_digit[i] = (a->ob_digit[j] >> loshift) & lomask; if (i+1 < newsize) z->ob_digit[i] |= (a->ob_digit[j+1] << hishift) & himask; } - z = long_normalize(z); + z = maybe_small_long(long_normalize(z)); } - rshift_error: - return (PyObject *) maybe_small_long(z); - + return (PyObject *)z; } static PyObject * -- cgit v1.2.1 From a92d1fa671171aa0da569aa91c7c75612a3ecacc Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sat, 17 Sep 2016 19:44:13 +0100 Subject: Issue #27441: Remove some redundant assignments to ob_size in longobject.c. Thanks Oren Milman. --- Objects/longobject.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'Objects') diff --git a/Objects/longobject.c b/Objects/longobject.c index 0822f9bcb3..0ecbab1fba 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -315,7 +315,6 @@ PyLong_FromUnsignedLong(unsigned long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->ob_digit; - Py_SIZE(v) = ndigits; while (ival) { *p++ = (digit)(ival & PyLong_MASK); ival >>= PyLong_SHIFT; @@ -1102,7 +1101,6 @@ PyLong_FromUnsignedLongLong(unsigned long long ival) v = _PyLong_New(ndigits); if (v != NULL) { digit *p = v->ob_digit; - Py_SIZE(v) = ndigits; while (ival) { *p++ = (digit)(ival & PyLong_MASK); ival >>= PyLong_SHIFT; -- cgit v1.2.1 From f90cefa36daf2409987e60421306c2a5948cd367 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Sat, 17 Sep 2016 20:01:56 +0100 Subject: Issue #27111: Minor simplication to long_add and long_sub fast path code. Thanks Oren Milman. --- Objects/longobject.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'Objects') diff --git a/Objects/longobject.c b/Objects/longobject.c index 0ecbab1fba..6e569b218d 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -3103,9 +3103,7 @@ long_add(PyLongObject *a, PyLongObject *b) CHECK_BINOP(a, b); if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) { - PyObject *result = PyLong_FromLong(MEDIUM_VALUE(a) + - MEDIUM_VALUE(b)); - return result; + return PyLong_FromLong(MEDIUM_VALUE(a) + MEDIUM_VALUE(b)); } if (Py_SIZE(a) < 0) { if (Py_SIZE(b) < 0) { @@ -3139,9 +3137,7 @@ long_sub(PyLongObject *a, PyLongObject *b) CHECK_BINOP(a, b); if (Py_ABS(Py_SIZE(a)) <= 1 && Py_ABS(Py_SIZE(b)) <= 1) { - PyObject* r; - r = PyLong_FromLong(MEDIUM_VALUE(a)-MEDIUM_VALUE(b)); - return r; + return PyLong_FromLong(MEDIUM_VALUE(a) - MEDIUM_VALUE(b)); } if (Py_SIZE(a) < 0) { if (Py_SIZE(b) < 0) -- cgit v1.2.1 From b384a4aaa907218aebcb9d60e22afcc30301a3c6 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 28 Sep 2016 07:53:32 +0300 Subject: Issue #28289: ImportError.__init__ now resets not specified attributes. --- Objects/exceptions.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'Objects') diff --git a/Objects/exceptions.c b/Objects/exceptions.c index f63f06a145..bc0264a5e9 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -631,19 +631,17 @@ ImportError_init(PyImportErrorObject *self, PyObject *args, PyObject *kwds) } Py_DECREF(empty_tuple); - if (name) { - Py_INCREF(name); - Py_XSETREF(self->name, name); - } - if (path) { - Py_INCREF(path); - Py_XSETREF(self->path, path); - } + Py_XINCREF(name); + Py_XSETREF(self->name, name); + + Py_XINCREF(path); + Py_XSETREF(self->path, path); + if (PyTuple_GET_SIZE(args) == 1) { msg = PyTuple_GET_ITEM(args, 0); Py_INCREF(msg); - Py_XSETREF(self->msg, msg); } + Py_XSETREF(self->msg, msg); return 0; } -- cgit v1.2.1 From 5ff197a8b9035f11b7c0529aa856c51eb29e96a2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 8 Oct 2016 22:01:18 +0300 Subject: Issue #28376: Creating instances of range_iterator by calling range_iterator type now is disallowed. Calling iter() on range instance is the only way. Patch by Oren Milman. --- Objects/rangeobject.c | 41 ----------------------------------------- 1 file changed, 41 deletions(-) (limited to 'Objects') diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 8449fc7a24..45c557ff57 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -829,8 +829,6 @@ static PyMethodDef rangeiter_methods[] = { {NULL, NULL} /* sentinel */ }; -static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw); - PyTypeObject PyRangeIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "range_iterator", /* tp_name */ @@ -862,15 +860,6 @@ PyTypeObject PyRangeIter_Type = { (iternextfunc)rangeiter_next, /* tp_iternext */ rangeiter_methods, /* 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 */ - rangeiter_new, /* tp_new */ }; /* Return number of items in range (lo, hi, step). step != 0 @@ -925,36 +914,6 @@ fast_range_iter(long start, long stop, long step) return (PyObject *)it; } -static PyObject * -rangeiter_new(PyTypeObject *type, PyObject *args, PyObject *kw) -{ - long start, stop, step; - - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "range_iterator(): creating instances of range_iterator " - "by calling range_iterator type is deprecated", - 1)) { - return NULL; - } - - if (!_PyArg_NoKeywords("range_iterator()", kw)) { - return NULL; - } - - if (!PyArg_ParseTuple(args, - "lll;range_iterator() requires 3 int arguments", - &start, &stop, &step)) { - return NULL; - } - if (step == 0) { - PyErr_SetString(PyExc_ValueError, - "range_iterator() arg 3 must not be zero"); - return NULL; - } - - return fast_range_iter(start, stop, step); -} - typedef struct { PyObject_HEAD PyObject *index; -- cgit v1.2.1 From 145f9db4a999a387c22e735e37918e3c0b28228a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 9 Oct 2016 23:44:48 +0300 Subject: Issue #28400: Removed uncessary checks in unicode_char and resize_copy. 1. In resize_copy we don't need to PyUnicode_READY(unicode) since when it's not PyUnicode_WCHAR_KIND it should be ready. 2. In unicode_char, PyUnicode_1BYTE_KIND is handled by get_latin1_char. Patch by Xiang Zhang. --- Objects/unicodeobject.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'Objects') diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index b58cf02a8c..8f34e01232 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1029,8 +1029,7 @@ resize_copy(PyObject *unicode, Py_ssize_t length) if (_PyUnicode_KIND(unicode) != PyUnicode_WCHAR_KIND) { PyObject *copy; - if (PyUnicode_READY(unicode) == -1) - return NULL; + assert(PyUnicode_IS_READY(unicode)); copy = PyUnicode_New(length, PyUnicode_MAX_CHAR_VALUE(unicode)); if (copy == NULL) @@ -1974,14 +1973,11 @@ unicode_char(Py_UCS4 ch) unicode = PyUnicode_New(1, ch); if (unicode == NULL) return NULL; - switch (PyUnicode_KIND(unicode)) { - case PyUnicode_1BYTE_KIND: - PyUnicode_1BYTE_DATA(unicode)[0] = (Py_UCS1)ch; - break; - case PyUnicode_2BYTE_KIND: + + assert(PyUnicode_KIND(unicode) != PyUnicode_1BYTE_KIND); + if (PyUnicode_KIND(unicode) == PyUnicode_2BYTE_KIND) { PyUnicode_2BYTE_DATA(unicode)[0] = (Py_UCS2)ch; - break; - default: + } else { assert(PyUnicode_KIND(unicode) == PyUnicode_4BYTE_KIND); PyUnicode_4BYTE_DATA(unicode)[0] = ch; } -- cgit v1.2.1 From 3205d08e1dfb682af590ee0146ff270c6b815606 Mon Sep 17 00:00:00 2001 From: doko Date: Tue, 11 Oct 2016 08:04:02 +0200 Subject: - dictobject.c: Make dict_merge symbol a static symbol --- Objects/dictobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 164bc180aa..03c973be63 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2372,7 +2372,7 @@ Return: return Py_SAFE_DOWNCAST(i, Py_ssize_t, int); } -int +static int dict_merge(PyObject *a, PyObject *b, int override) { PyDictObject *mp, *other; -- cgit v1.2.1 From 6f8c51b8f9c626f1e4c6a541812ca4d131a13aa0 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 22 Oct 2016 09:58:14 -0700 Subject: Reference the original compact-and-ordered proposal --- Objects/dictobject.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 03c973be63..2cca2c678e 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -10,8 +10,9 @@ This implements the dictionary's hashtable. -As of Python 3.6, this is compact and ordered. Basic idea is described here. -https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html +As of Python 3.6, this is compact and ordered. Basic idea is described here: +* https://mail.python.org/pipermail/python-dev/2012-December/123028.html +* https://morepypy.blogspot.com/2015/01/faster-more-memory-efficient-and-more.html layout: -- cgit v1.2.1 From 1838227e043f62a985ee112c3666b214696a27d7 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 22 Oct 2016 23:18:31 +0300 Subject: Issue #28504: Cleanup unicode_decode_call_errorhandler_wchar/writer. Patch by Xiang Zhang. --- Objects/unicodeobject.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'Objects') diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 05f4d30e08..af95bb6b4a 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4240,7 +4240,7 @@ unicode_decode_call_errorhandler_wchar( Py_ssize_t *endinpos, PyObject **exceptionObject, const char **inptr, PyObject **output, Py_ssize_t *outpos) { - static const char *argparse = "O!n;decoding error handler must return (str, int) tuple"; + static const char *argparse = "Un;decoding error handler must return (str, int) tuple"; PyObject *restuple = NULL; PyObject *repunicode = NULL; @@ -4273,10 +4273,10 @@ unicode_decode_call_errorhandler_wchar( if (restuple == NULL) goto onError; if (!PyTuple_Check(restuple)) { - PyErr_SetString(PyExc_TypeError, &argparse[4]); + PyErr_SetString(PyExc_TypeError, &argparse[3]); goto onError; } - if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, &repunicode, &newpos)) + if (!PyArg_ParseTuple(restuple, argparse, &repunicode, &newpos)) goto onError; /* Copy back the bytes variables, which might have been modified by the @@ -4284,9 +4284,6 @@ unicode_decode_call_errorhandler_wchar( inputobj = PyUnicodeDecodeError_GetObject(*exceptionObject); if (!inputobj) goto onError; - if (!PyBytes_Check(inputobj)) { - PyErr_Format(PyExc_TypeError, "exception attribute object must be bytes"); - } *input = PyBytes_AS_STRING(inputobj); insize = PyBytes_GET_SIZE(inputobj); *inend = *input + insize; @@ -4327,7 +4324,7 @@ unicode_decode_call_errorhandler_wchar( *inptr = *input + newpos; /* we made it! */ - Py_XDECREF(restuple); + Py_DECREF(restuple); return 0; overflow: @@ -4348,7 +4345,7 @@ unicode_decode_call_errorhandler_writer( Py_ssize_t *endinpos, PyObject **exceptionObject, const char **inptr, _PyUnicodeWriter *writer /* PyObject **output, Py_ssize_t *outpos */) { - static const char *argparse = "O!n;decoding error handler must return (str, int) tuple"; + static const char *argparse = "Un;decoding error handler must return (str, int) tuple"; PyObject *restuple = NULL; PyObject *repunicode = NULL; @@ -4375,10 +4372,10 @@ unicode_decode_call_errorhandler_writer( if (restuple == NULL) goto onError; if (!PyTuple_Check(restuple)) { - PyErr_SetString(PyExc_TypeError, &argparse[4]); + PyErr_SetString(PyExc_TypeError, &argparse[3]); goto onError; } - if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, &repunicode, &newpos)) + if (!PyArg_ParseTuple(restuple, argparse, &repunicode, &newpos)) goto onError; /* Copy back the bytes variables, which might have been modified by the @@ -4386,9 +4383,6 @@ unicode_decode_call_errorhandler_writer( inputobj = PyUnicodeDecodeError_GetObject(*exceptionObject); if (!inputobj) goto onError; - if (!PyBytes_Check(inputobj)) { - PyErr_Format(PyExc_TypeError, "exception attribute object must be bytes"); - } *input = PyBytes_AS_STRING(inputobj); insize = PyBytes_GET_SIZE(inputobj); *inend = *input + insize; @@ -4403,8 +4397,6 @@ unicode_decode_call_errorhandler_writer( goto onError; } - if (PyUnicode_READY(repunicode) < 0) - goto onError; replen = PyUnicode_GET_LENGTH(repunicode); if (replen > 1) { writer->min_length += replen - 1; @@ -4420,7 +4412,7 @@ unicode_decode_call_errorhandler_writer( *inptr = *input + newpos; /* we made it! */ - Py_XDECREF(restuple); + Py_DECREF(restuple); return 0; onError: -- cgit v1.2.1 From 6ed55b2d31ec9afacbecd309d2c3a4c099848a6c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 23 Oct 2016 15:12:25 +0300 Subject: Issue #28511: Use the "U" format instead of "O!" in PyArg_Parse*. --- Objects/exceptions.c | 33 ++++++++++----------------------- Objects/unicodeobject.c | 6 +++--- 2 files changed, 13 insertions(+), 26 deletions(-) (limited to 'Objects') diff --git a/Objects/exceptions.c b/Objects/exceptions.c index bc0264a5e9..57a786c022 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -1820,18 +1820,10 @@ UnicodeEncodeError_init(PyObject *self, PyObject *args, PyObject *kwds) Py_CLEAR(err->object); Py_CLEAR(err->reason); - if (!PyArg_ParseTuple(args, "O!O!nnO!", - &PyUnicode_Type, &err->encoding, - &PyUnicode_Type, &err->object, - &err->start, - &err->end, - &PyUnicode_Type, &err->reason)) { - err->encoding = err->object = err->reason = NULL; - return -1; - } - - if (PyUnicode_READY(err->object) < -1) { - err->encoding = NULL; + if (!PyArg_ParseTuple(args, "UUnnU", + &err->encoding, &err->object, + &err->start, &err->end, &err->reason)) { + err->encoding = err->object = err->reason = NULL; return -1; } @@ -1935,12 +1927,9 @@ UnicodeDecodeError_init(PyObject *self, PyObject *args, PyObject *kwds) Py_CLEAR(ude->object); Py_CLEAR(ude->reason); - if (!PyArg_ParseTuple(args, "O!OnnO!", - &PyUnicode_Type, &ude->encoding, - &ude->object, - &ude->start, - &ude->end, - &PyUnicode_Type, &ude->reason)) { + if (!PyArg_ParseTuple(args, "UOnnU", + &ude->encoding, &ude->object, + &ude->start, &ude->end, &ude->reason)) { ude->encoding = ude->object = ude->reason = NULL; return -1; } @@ -2050,11 +2039,9 @@ UnicodeTranslateError_init(PyUnicodeErrorObject *self, PyObject *args, Py_CLEAR(self->object); Py_CLEAR(self->reason); - if (!PyArg_ParseTuple(args, "O!nnO!", - &PyUnicode_Type, &self->object, - &self->start, - &self->end, - &PyUnicode_Type, &self->reason)) { + if (!PyArg_ParseTuple(args, "UnnU", + &self->object, + &self->start, &self->end, &self->reason)) { self->object = self->reason = NULL; return -1; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index af95bb6b4a..6ab691ff25 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -8621,7 +8621,7 @@ unicode_translate_call_errorhandler(const char *errors, Py_ssize_t startpos, Py_ssize_t endpos, Py_ssize_t *newpos) { - static const char *argparse = "O!n;translating error handler must return (str, int) tuple"; + static const char *argparse = "Un;translating error handler must return (str, int) tuple"; Py_ssize_t i_newpos; PyObject *restuple; @@ -8643,11 +8643,11 @@ unicode_translate_call_errorhandler(const char *errors, if (restuple == NULL) return NULL; if (!PyTuple_Check(restuple)) { - PyErr_SetString(PyExc_TypeError, &argparse[4]); + PyErr_SetString(PyExc_TypeError, &argparse[3]); Py_DECREF(restuple); return NULL; } - if (!PyArg_ParseTuple(restuple, argparse, &PyUnicode_Type, + if (!PyArg_ParseTuple(restuple, argparse, &resunicode, &i_newpos)) { Py_DECREF(restuple); return NULL; -- cgit v1.2.1 From 5303b85718c671e17716d3ddfb4f1440ca4abef0 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 23 Oct 2016 15:41:36 +0300 Subject: Issue #28439: Remove redundant checks in PyUnicode_EncodeLocale and PyUnicode_DecodeLocaleAndSize. Patch by Xiang Zhang. --- Objects/unicodeobject.c | 47 ++++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) (limited to 'Objects') diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 6ab691ff25..cd8b33c594 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3400,11 +3400,9 @@ PyUnicode_EncodeLocale(PyObject *unicode, const char *errors) { Py_ssize_t wlen, wlen2; wchar_t *wstr; - PyObject *bytes = NULL; char *errmsg; - PyObject *reason = NULL; - PyObject *exc; - size_t error_pos; + PyObject *bytes, *reason, *exc; + size_t error_pos, errlen; int surrogateescape; if (locale_error_handler(errors, &surrogateescape) < 0) @@ -3459,6 +3457,7 @@ PyUnicode_EncodeLocale(PyObject *unicode, const char *errors) len2 = wcstombs(PyBytes_AS_STRING(bytes), wstr, len+1); if (len2 == (size_t)-1 || len2 > len) { + Py_DECREF(bytes); error_pos = (size_t)-1; goto encode_error; } @@ -3474,17 +3473,15 @@ encode_error: error_pos = wcstombs_errorpos(wstr); PyMem_Free(wstr); - Py_XDECREF(bytes); - - if (errmsg != NULL) { - size_t errlen; - wstr = Py_DecodeLocale(errmsg, &errlen); - if (wstr != NULL) { - reason = PyUnicode_FromWideChar(wstr, errlen); - PyMem_RawFree(wstr); - } else - errmsg = NULL; + + wstr = Py_DecodeLocale(errmsg, &errlen); + if (wstr != NULL) { + reason = PyUnicode_FromWideChar(wstr, errlen); + PyMem_RawFree(wstr); + } else { + errmsg = NULL; } + if (errmsg == NULL) reason = PyUnicode_FromString( "wcstombs() encountered an unencodable " @@ -3500,7 +3497,7 @@ encode_error: Py_DECREF(reason); if (exc != NULL) { PyCodec_StrictErrors(exc); - Py_XDECREF(exc); + Py_DECREF(exc); } return NULL; } @@ -3702,10 +3699,9 @@ PyUnicode_DecodeLocaleAndSize(const char *str, Py_ssize_t len, size_t wlen, wlen2; PyObject *unicode; int surrogateescape; - size_t error_pos; + size_t error_pos, errlen; char *errmsg; - PyObject *reason = NULL; /* initialize to prevent gcc warning */ - PyObject *exc; + PyObject *exc, *reason = NULL; /* initialize to prevent gcc warning */ if (locale_error_handler(errors, &surrogateescape) < 0) return NULL; @@ -3763,19 +3759,16 @@ PyUnicode_DecodeLocaleAndSize(const char *str, Py_ssize_t len, return unicode; decode_error: - reason = NULL; errmsg = strerror(errno); assert(errmsg != NULL); error_pos = mbstowcs_errorpos(str, len); - if (errmsg != NULL) { - size_t errlen; - wstr = Py_DecodeLocale(errmsg, &errlen); - if (wstr != NULL) { - reason = PyUnicode_FromWideChar(wstr, errlen); - PyMem_RawFree(wstr); - } + wstr = Py_DecodeLocale(errmsg, &errlen); + if (wstr != NULL) { + reason = PyUnicode_FromWideChar(wstr, errlen); + PyMem_RawFree(wstr); } + if (reason == NULL) reason = PyUnicode_FromString( "mbstowcs() encountered an invalid multibyte sequence"); @@ -3790,7 +3783,7 @@ decode_error: Py_DECREF(reason); if (exc != NULL) { PyCodec_StrictErrors(exc); - Py_XDECREF(exc); + Py_DECREF(exc); } return NULL; } -- cgit v1.2.1 From 770891917b1ffe9eb66e72c61355c3a95d4a6db5 Mon Sep 17 00:00:00 2001 From: "Eric V. Smith" Date: Mon, 31 Oct 2016 09:22:08 -0400 Subject: Issue 28128: Print out better error/warning messages for invalid string escapes. --- Objects/bytesobject.c | 37 +++++++++++++++++++++++++++++++++---- Objects/unicodeobject.c | 38 ++++++++++++++++++++++++++++++++------ 2 files changed, 65 insertions(+), 10 deletions(-) (limited to 'Objects') diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 598f6a13cf..779fe295db 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -1105,11 +1105,12 @@ _PyBytes_DecodeEscapeRecode(const char **s, const char *end, return p; } -PyObject *PyBytes_DecodeEscape(const char *s, +PyObject *_PyBytes_DecodeEscape(const char *s, Py_ssize_t len, const char *errors, Py_ssize_t unicode, - const char *recode_encoding) + const char *recode_encoding, + const char **first_invalid_escape) { int c; char *p; @@ -1123,6 +1124,8 @@ PyObject *PyBytes_DecodeEscape(const char *s, return NULL; writer.overallocate = 1; + *first_invalid_escape = NULL; + end = s + len; while (s < end) { if (*s != '\\') { @@ -1207,9 +1210,12 @@ PyObject *PyBytes_DecodeEscape(const char *s, break; default: - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, "invalid escape sequence '\\%c'", *(--s)) < 0) - goto failed; + if (*first_invalid_escape == NULL) { + *first_invalid_escape = s-1; /* Back up one char, since we've + already incremented s. */ + } *p++ = '\\'; + s--; goto non_esc; /* an arbitrary number of unescaped UTF-8 bytes may follow. */ } @@ -1222,6 +1228,29 @@ PyObject *PyBytes_DecodeEscape(const char *s, return NULL; } +PyObject *PyBytes_DecodeEscape(const char *s, + Py_ssize_t len, + const char *errors, + Py_ssize_t unicode, + const char *recode_encoding) +{ + const char* first_invalid_escape; + PyObject *result = _PyBytes_DecodeEscape(s, len, errors, unicode, + recode_encoding, + &first_invalid_escape); + if (result == NULL) + return NULL; + if (first_invalid_escape != NULL) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "invalid escape sequence '\\%c'", + *first_invalid_escape) < 0) { + Py_DECREF(result); + return NULL; + } + } + return result; + +} /* -------------------------------------------------------------------- */ /* object api */ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 134fa07600..6e63e009a9 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -5877,9 +5877,10 @@ PyUnicode_AsUTF16String(PyObject *unicode) static _PyUnicode_Name_CAPI *ucnhash_CAPI = NULL; PyObject * -PyUnicode_DecodeUnicodeEscape(const char *s, - Py_ssize_t size, - const char *errors) +_PyUnicode_DecodeUnicodeEscape(const char *s, + Py_ssize_t size, + const char *errors, + const char **first_invalid_escape) { const char *starts = s; _PyUnicodeWriter writer; @@ -5887,6 +5888,9 @@ PyUnicode_DecodeUnicodeEscape(const char *s, PyObject *errorHandler = NULL; PyObject *exc = NULL; + // so we can remember if we've seen an invalid escape char or not + *first_invalid_escape = NULL; + if (size == 0) { _Py_RETURN_UNICODE_EMPTY(); } @@ -6061,9 +6065,10 @@ PyUnicode_DecodeUnicodeEscape(const char *s, goto error; default: - if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "invalid escape sequence '\\%c'", c) < 0) - goto onError; + if (*first_invalid_escape == NULL) { + *first_invalid_escape = s-1; /* Back up one char, since we've + already incremented s. */ + } WRITE_ASCII_CHAR('\\'); WRITE_CHAR(c); continue; @@ -6098,6 +6103,27 @@ PyUnicode_DecodeUnicodeEscape(const char *s, return NULL; } +PyObject * +PyUnicode_DecodeUnicodeEscape(const char *s, + Py_ssize_t size, + const char *errors) +{ + const char *first_invalid_escape; + PyObject *result = _PyUnicode_DecodeUnicodeEscape(s, size, errors, + &first_invalid_escape); + if (result == NULL) + return NULL; + if (first_invalid_escape != NULL) { + if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, + "invalid escape sequence '\\%c'", + *first_invalid_escape) < 0) { + Py_DECREF(result); + return NULL; + } + } + return result; +} + /* Return a Unicode-Escape string version of the Unicode object. If quotes is true, the string is enclosed in u"" or u'' quotes as -- cgit v1.2.1 From af0cb9c1e35bb720a3ad0b01e8d9607bb92d0455 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Fri, 4 Nov 2016 16:59:10 +0900 Subject: Issue #28580: Optimize iterating split table values. Patch by Xiang Zhang. --- Objects/dictobject.c | 62 +++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 37 deletions(-) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 30062cb775..85ada6cc5f 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1700,7 +1700,7 @@ int _PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue, Py_hash_t *phash) { - Py_ssize_t i, n; + Py_ssize_t i; PyDictObject *mp; PyDictKeyEntry *entry_ptr; PyObject *value; @@ -1709,21 +1709,18 @@ _PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, return 0; mp = (PyDictObject *)op; i = *ppos; - n = mp->ma_keys->dk_nentries; - if ((size_t)i >= (size_t)n) - return 0; if (mp->ma_values) { - PyObject **value_ptr = &mp->ma_values[i]; - while (i < n && *value_ptr == NULL) { - value_ptr++; - i++; - } - if (i >= n) + if (i < 0 || i >= mp->ma_used) return 0; + /* values of split table is always dense */ entry_ptr = &DK_ENTRIES(mp->ma_keys)[i]; - value = *value_ptr; + value = mp->ma_values[i]; + assert(value != NULL); } else { + Py_ssize_t n = mp->ma_keys->dk_nentries; + if (i < 0 || i >= n) + return 0; entry_ptr = &DK_ENTRIES(mp->ma_keys)[i]; while (i < n && entry_ptr->me_value == NULL) { entry_ptr++; @@ -3380,7 +3377,7 @@ static PyObject* dictiter_iternextkey(dictiterobject *di) { PyObject *key; - Py_ssize_t i, n; + Py_ssize_t i; PyDictKeysObject *k; PyDictObject *d = di->di_dict; @@ -3397,18 +3394,15 @@ dictiter_iternextkey(dictiterobject *di) i = di->di_pos; k = d->ma_keys; - n = k->dk_nentries; + assert(i >= 0); if (d->ma_values) { - PyObject **value_ptr = &d->ma_values[i]; - while (i < n && *value_ptr == NULL) { - value_ptr++; - i++; - } - if (i >= n) + if (i >= d->ma_used) goto fail; key = DK_ENTRIES(k)[i].me_key; + assert(d->ma_values[i] != NULL); } else { + Py_ssize_t n = k->dk_nentries; PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i]; while (i < n && entry_ptr->me_value == NULL) { entry_ptr++; @@ -3466,7 +3460,7 @@ static PyObject * dictiter_iternextvalue(dictiterobject *di) { PyObject *value; - Py_ssize_t i, n; + Py_ssize_t i; PyDictObject *d = di->di_dict; if (d == NULL) @@ -3481,18 +3475,15 @@ dictiter_iternextvalue(dictiterobject *di) } i = di->di_pos; - n = d->ma_keys->dk_nentries; + assert(i >= 0); if (d->ma_values) { - PyObject **value_ptr = &d->ma_values[i]; - while (i < n && *value_ptr == NULL) { - value_ptr++; - i++; - } - if (i >= n) + if (i >= d->ma_used) goto fail; - value = *value_ptr; + value = d->ma_values[i]; + assert(value != NULL); } else { + Py_ssize_t n = d->ma_keys->dk_nentries; PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i]; while (i < n && entry_ptr->me_value == NULL) { entry_ptr++; @@ -3550,7 +3541,7 @@ static PyObject * dictiter_iternextitem(dictiterobject *di) { PyObject *key, *value, *result = di->di_result; - Py_ssize_t i, n; + Py_ssize_t i; PyDictObject *d = di->di_dict; if (d == NULL) @@ -3565,19 +3556,16 @@ dictiter_iternextitem(dictiterobject *di) } i = di->di_pos; - n = d->ma_keys->dk_nentries; + assert(i >= 0); if (d->ma_values) { - PyObject **value_ptr = &d->ma_values[i]; - while (i < n && *value_ptr == NULL) { - value_ptr++; - i++; - } - if (i >= n) + if (i >= d->ma_used) goto fail; key = DK_ENTRIES(d->ma_keys)[i].me_key; - value = *value_ptr; + value = d->ma_values[i]; + assert(value != NULL); } else { + Py_ssize_t n = d->ma_keys->dk_nentries; PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i]; while (i < n && entry_ptr->me_value == NULL) { entry_ptr++; -- cgit v1.2.1 From d4870f38df7c4e96b5c4eb684e904465e39080f3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 29 Oct 2016 10:50:00 +0300 Subject: Issue #28199: Microoptimized dict resizing. Based on patch by Naoki Inada. --- Objects/dictobject.c | 123 ++++++++++++++++++++++++++------------------------- 1 file changed, 63 insertions(+), 60 deletions(-) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 9bf4eeef41..cb67dda33f 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1198,41 +1198,21 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) } /* -Internal routine used by dictresize() to insert an item which is -known to be absent from the dict. This routine also assumes that -the dict contains no deleted entries. Besides the performance benefit, -using insertdict() in dictresize() is dangerous (SF bug #1456209). -Note that no refcounts are changed by this routine; if needed, the caller -is responsible for incref'ing `key` and `value`. -Neither mp->ma_used nor k->dk_usable are modified by this routine; the caller -must set them correctly +Internal routine used by dictresize() to buid a hashtable of entries. */ static void -insertdict_clean(PyDictObject *mp, PyObject *key, Py_hash_t hash, - PyObject *value) +build_indices(PyDictKeysObject *keys, PyDictKeyEntry *ep, Py_ssize_t n) { - size_t i; - PyDictKeysObject *k = mp->ma_keys; - size_t mask = (size_t)DK_SIZE(k)-1; - PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys); - PyDictKeyEntry *ep; - - assert(k->dk_lookup != NULL); - assert(value != NULL); - assert(key != NULL); - assert(PyUnicode_CheckExact(key) || k->dk_lookup == lookdict); - i = hash & mask; - for (size_t perturb = hash; dk_get_index(k, i) != DKIX_EMPTY;) { - perturb >>= PERTURB_SHIFT; - i = mask & ((i << 2) + i + perturb + 1); + size_t mask = (size_t)DK_SIZE(keys) - 1; + for (Py_ssize_t ix = 0; ix != n; ix++, ep++) { + Py_hash_t hash = ep->me_hash; + size_t i = hash & mask; + for (size_t perturb = hash; dk_get_index(keys, i) != DKIX_EMPTY;) { + perturb >>= PERTURB_SHIFT; + i = mask & ((i << 2) + i + perturb + 1); + } + dk_set_index(keys, i, ix); } - ep = &ep0[k->dk_nentries]; - assert(ep->me_value == NULL); - dk_set_index(k, i, k->dk_nentries); - k->dk_nentries++; - ep->me_key = key; - ep->me_hash = hash; - ep->me_value = value; } /* @@ -1248,10 +1228,10 @@ but can be resplit by make_keys_shared(). static int dictresize(PyDictObject *mp, Py_ssize_t minused) { - Py_ssize_t i, newsize; + Py_ssize_t newsize, numentries; PyDictKeysObject *oldkeys; PyObject **oldvalues; - PyDictKeyEntry *ep0; + PyDictKeyEntry *oldentries, *newentries; /* Find the smallest table size > minused. */ for (newsize = PyDict_MINSIZE; @@ -1262,8 +1242,14 @@ dictresize(PyDictObject *mp, Py_ssize_t minused) PyErr_NoMemory(); return -1; } + oldkeys = mp->ma_keys; - oldvalues = mp->ma_values; + + /* NOTE: Current odict checks mp->ma_keys to detect resize happen. + * So we can't reuse oldkeys even if oldkeys->dk_size == newsize. + * TODO: Try reusing oldkeys when reimplement odict. + */ + /* Allocate a new table. */ mp->ma_keys = new_keys_object(newsize); if (mp->ma_keys == NULL) { @@ -1272,42 +1258,59 @@ dictresize(PyDictObject *mp, Py_ssize_t minused) } if (oldkeys->dk_lookup == lookdict) mp->ma_keys->dk_lookup = lookdict; - mp->ma_values = NULL; - ep0 = DK_ENTRIES(oldkeys); - /* Main loop below assumes we can transfer refcount to new keys - * and that value is stored in me_value. - * Increment ref-counts and copy values here to compensate - * This (resizing a split table) should be relatively rare */ + + numentries = mp->ma_used; + oldentries = DK_ENTRIES(oldkeys); + newentries = DK_ENTRIES(mp->ma_keys); + oldvalues = mp->ma_values; if (oldvalues != NULL) { - for (i = 0; i < oldkeys->dk_nentries; i++) { - if (oldvalues[i] != NULL) { - Py_INCREF(ep0[i].me_key); - ep0[i].me_value = oldvalues[i]; - } - } - } - /* Main loop */ - for (i = 0; i < oldkeys->dk_nentries; i++) { - PyDictKeyEntry *ep = &ep0[i]; - if (ep->me_value != NULL) { - insertdict_clean(mp, ep->me_key, ep->me_hash, ep->me_value); + /* Convert split table into new combined table. + * We must incref keys; we can transfer values. + * Note that values of split table is always dense. + */ + for (Py_ssize_t i = 0; i < numentries; i++) { + assert(oldvalues[i] != NULL); + PyDictKeyEntry *ep = &oldentries[i]; + PyObject *key = ep->me_key; + Py_INCREF(key); + newentries[i].me_key = key; + newentries[i].me_hash = ep->me_hash; + newentries[i].me_value = oldvalues[i]; } - } - mp->ma_keys->dk_usable -= mp->ma_used; - if (oldvalues != NULL) { - /* NULL out me_value slot in oldkeys, in case it was shared */ - for (i = 0; i < oldkeys->dk_nentries; i++) - ep0[i].me_value = NULL; + DK_DECREF(oldkeys); + mp->ma_values = NULL; if (oldvalues != empty_values) { free_values(oldvalues); } } - else { + else { // combined table. + if (oldkeys->dk_nentries == numentries) { + memcpy(newentries, oldentries, numentries * sizeof(PyDictKeyEntry)); + } + else { + PyDictKeyEntry *ep = oldentries; + for (Py_ssize_t i = 0; i < numentries; i++) { + while (ep->me_value == NULL) + ep++; + newentries[i] = *ep++; + } + } + assert(oldkeys->dk_lookup != lookdict_split); assert(oldkeys->dk_refcnt == 1); - DK_DEBUG_DECREF PyObject_FREE(oldkeys); + if (oldkeys->dk_size == PyDict_MINSIZE && + numfreekeys < PyDict_MAXFREELIST) { + DK_DEBUG_DECREF keys_free_list[numfreekeys++] = oldkeys; + } + else { + DK_DEBUG_DECREF PyObject_FREE(oldkeys); + } } + + build_indices(mp->ma_keys, newentries, numentries); + mp->ma_keys->dk_usable -= numentries; + mp->ma_keys->dk_nentries = numentries; return 0; } -- cgit v1.2.1 From a501fdb581467719292dbdeec07242d10de3555d Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 8 Nov 2016 20:34:22 +0200 Subject: Issue #28621: Sped up converting int to float by reusing faster bits counting implementation. Patch by Adrian Wielgosik. --- Objects/longobject.c | 60 ++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 32 deletions(-) (limited to 'Objects') diff --git a/Objects/longobject.c b/Objects/longobject.c index 6e569b218d..10dde726a2 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -708,12 +708,33 @@ _PyLong_Sign(PyObject *vv) return Py_SIZE(v) == 0 ? 0 : (Py_SIZE(v) < 0 ? -1 : 1); } +/* bits_in_digit(d) returns the unique integer k such that 2**(k-1) <= d < + 2**k if d is nonzero, else 0. */ + +static const unsigned char BitLengthTable[32] = { + 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 +}; + +static int +bits_in_digit(digit d) +{ + int d_bits = 0; + while (d >= 32) { + d_bits += 6; + d >>= 6; + } + d_bits += (int)BitLengthTable[d]; + return d_bits; +} + size_t _PyLong_NumBits(PyObject *vv) { PyLongObject *v = (PyLongObject *)vv; size_t result = 0; Py_ssize_t ndigits; + int msd_bits; assert(v != NULL); assert(PyLong_Check(v)); @@ -724,12 +745,10 @@ _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; - do { - ++result; - if (result == 0) - goto Overflow; - msd >>= 1; - } while (msd); + msd_bits = bits_in_digit(msd); + if (SIZE_MAX - msd_bits < result) + goto Overflow; + result += msd_bits; } return result; @@ -1414,26 +1433,6 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow) Py_RETURN_NOTIMPLEMENTED; \ } while(0) -/* bits_in_digit(d) returns the unique integer k such that 2**(k-1) <= d < - 2**k if d is nonzero, else 0. */ - -static const unsigned char BitLengthTable[32] = { - 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 -}; - -static int -bits_in_digit(digit d) -{ - int d_bits = 0; - while (d >= 32) { - d_bits += 6; - d >>= 6; - } - d_bits += (int)BitLengthTable[d]; - return d_bits; -} - /* x[0:m] and y[0:n] are digit vectors, LSD first, m >= n required. x[0:n] * is modified in place, by adding y to it. Carries are propagated as far as * x[m-1], and the remaining carry (0 or 1) is returned. @@ -5079,7 +5078,8 @@ static PyObject * long_bit_length(PyLongObject *v) { PyLongObject *result, *x, *y; - Py_ssize_t ndigits, msd_bits = 0; + Py_ssize_t ndigits; + int msd_bits; digit msd; assert(v != NULL); @@ -5090,11 +5090,7 @@ long_bit_length(PyLongObject *v) return PyLong_FromLong(0); msd = v->ob_digit[ndigits-1]; - while (msd >= 32) { - msd_bits += 6; - msd >>= 6; - } - msd_bits += (long)(BitLengthTable[msd]); + msd_bits = bits_in_digit(msd); if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT) return PyLong_FromSsize_t((ndigits-1)*PyLong_SHIFT + msd_bits); -- cgit v1.2.1 From bc2f49454c330a83373e1f00c3de717dad4070ef Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 11 Nov 2016 01:43:56 +0100 Subject: Use PyThreadState_GET() in performance critical code It seems like _PyThreadState_UncheckedGet() is not inlined as expected, even when using gcc -O3. --- Objects/dictobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index cb67dda33f..290686b88f 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1409,7 +1409,7 @@ PyDict_GetItem(PyObject *op, PyObject *key) Let's just hope that no exception occurs then... This must be _PyThreadState_Current and not PyThreadState_GET() because in debug mode, the latter complains if tstate is NULL. */ - tstate = _PyThreadState_UncheckedGet(); + tstate = PyThreadState_GET(); if (tstate != NULL && tstate->curexc_type != NULL) { /* preserve the existing exception */ PyObject *err_type, *err_value, *err_tb; -- cgit v1.2.1 From 18dea7d67d8b263dd8b49e1d44dcb09ca86ad08a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 11 Nov 2016 02:13:35 +0100 Subject: Issue #28618: Make hot functions using __attribute__((hot)) When Python is not compiled with PGO, the performance of Python on call_simple and call_method microbenchmarks depend highly on the code placement. In the worst case, the performance slowdown can be up to 70%. The GCC __attribute__((hot)) attribute helps to keep hot code close to reduce the risk of such major slowdown. This attribute is ignored when Python is compiled with PGO. The following functions are considered as hot according to statistics collected by perf record/perf report: * _PyEval_EvalFrameDefault() * call_function() * _PyFunction_FastCall() * PyFrame_New() * frame_dealloc() * PyErr_Occurred() --- Objects/frameobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Objects') diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 62f9f34c8e..eed538498c 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -409,7 +409,7 @@ static int numfree = 0; /* number of frames currently in free_list */ /* max value for numfree */ #define PyFrame_MAXFREELIST 200 -static void +static void _Py_HOT_FUNCTION frame_dealloc(PyFrameObject *f) { PyObject **p, **valuestack; @@ -605,7 +605,7 @@ int _PyFrame_Init() return 1; } -PyFrameObject * +PyFrameObject* _Py_HOT_FUNCTION PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, PyObject *locals) { -- cgit v1.2.1 From 980554ec4d992135f53e5a919047c835b7a68925 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 15 Nov 2016 15:13:40 +0100 Subject: Issue #28618: Mark dict lookup functions as hot It's common to see these functions in the top 3 of "perf report". --- Objects/dictobject.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 290686b88f..320dff6dfc 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -683,7 +683,7 @@ the value. For both, when the key isn't found a DKIX_EMPTY is returned. hashpos returns where the key index should be inserted. */ -static Py_ssize_t +static Py_ssize_t _Py_HOT_FUNCTION lookdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { @@ -798,7 +798,7 @@ top: } /* Specialized version for string-only keys */ -static Py_ssize_t +static Py_ssize_t _Py_HOT_FUNCTION lookdict_unicode(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { @@ -873,7 +873,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, /* Faster version of lookdict_unicode when it is known that no keys * will be present. */ -static Py_ssize_t +static Py_ssize_t _Py_HOT_FUNCTION lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) @@ -941,7 +941,7 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, * Split tables only contain unicode keys and no dummy keys, * so algorithm is the same as lookdict_unicode_nodummy. */ -static Py_ssize_t +static Py_ssize_t _Py_HOT_FUNCTION lookdict_split(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) { -- cgit v1.2.1 From 5d858465b6ebdafa05f86309457848cc26913b6a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 20 Nov 2016 10:16:47 +0200 Subject: Added the const qualifier to char* variables that refer to readonly internal UTF-8 represenatation of Unicode objects. --- Objects/fileobject.c | 8 +++----- Objects/floatobject.c | 6 +++--- Objects/longobject.c | 3 ++- Objects/moduleobject.c | 4 ++-- Objects/setobject.c | 2 +- Objects/structseq.c | 2 +- Objects/typeobject.c | 4 ++-- 7 files changed, 14 insertions(+), 15 deletions(-) (limited to 'Objects') diff --git a/Objects/fileobject.c b/Objects/fileobject.c index f4424184d2..32f8a8983e 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -367,7 +367,7 @@ stdprinter_write(PyStdPrinter_Object *self, PyObject *args) { PyObject *unicode; PyObject *bytes = NULL; - char *str; + const char *str; Py_ssize_t n; int err; @@ -389,10 +389,8 @@ stdprinter_write(PyStdPrinter_Object *self, PyObject *args) bytes = _PyUnicode_AsUTF8String(unicode, "backslashreplace"); if (bytes == NULL) return NULL; - if (PyBytes_AsStringAndSize(bytes, &str, &n) < 0) { - Py_DECREF(bytes); - return NULL; - } + str = PyBytes_AS_STRING(bytes); + n = PyBytes_GET_SIZE(bytes); } n = _Py_write(self->fd, str, n); diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 80bf71efd2..17a55dd114 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1225,7 +1225,7 @@ float_fromhex(PyObject *cls, PyObject *arg) PyObject *result; double x; long exp, top_exp, lsb, key_digit; - char *s, *coeff_start, *s_store, *coeff_end, *exp_start, *s_end; + const char *s, *coeff_start, *s_store, *coeff_end, *exp_start, *s_end; int half_eps, digit, round_up, negate=0; Py_ssize_t length, ndigits, fdigits, i; @@ -1288,7 +1288,7 @@ float_fromhex(PyObject *cls, PyObject *arg) s++; /* infinities and nans */ - x = _Py_parse_inf_or_nan(s, &coeff_end); + x = _Py_parse_inf_or_nan(s, (char **)&coeff_end); if (coeff_end != s) { s = coeff_end; goto finished; @@ -1619,7 +1619,7 @@ static float_format_type detected_double_format, detected_float_format; static PyObject * float_getformat(PyTypeObject *v, PyObject* arg) { - char* s; + const char *s; float_format_type r; if (!PyUnicode_Check(arg)) { diff --git a/Objects/longobject.c b/Objects/longobject.c index b0f6b8c953..822ed1632f 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2491,7 +2491,8 @@ PyObject * PyLong_FromUnicodeObject(PyObject *u, int base) { PyObject *result, *asciidig; - char *buffer, *end = NULL; + const char *buffer; + char *end = NULL; Py_ssize_t buflen; asciidig = _PyUnicode_TransformDecimalAndSpaceToASCII(u); diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 79be51a806..701bcb1df3 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -231,7 +231,7 @@ PyModule_FromDefAndSpec2(struct PyModuleDef* def, PyObject *spec, int module_api PyObject *nameobj; PyObject *m = NULL; int has_execution_slots = 0; - char *name; + const char *name; int ret; PyModuleDef_Init(def); @@ -512,7 +512,7 @@ const char * PyModule_GetFilename(PyObject *m) { PyObject *fileobj; - char *utf8; + const char *utf8; fileobj = PyModule_GetFilenameObject(m); if (fileobj == NULL) return NULL; diff --git a/Objects/setobject.c b/Objects/setobject.c index fdb9d3600d..b7e0617db3 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -2398,7 +2398,7 @@ static PyObject * test_c_api(PySetObject *so) { Py_ssize_t count; - char *s; + const char *s; Py_ssize_t i; PyObject *elem=NULL, *dup=NULL, *t, *f, *dup2, *x=NULL; PyObject *ob = (PyObject *)so; diff --git a/Objects/structseq.c b/Objects/structseq.c index 5489aef6d0..6f1782f29b 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -182,7 +182,7 @@ structseq_repr(PyStructSequence *obj) for (i=0; i < VISIBLE_SIZE(obj); i++) { PyObject *val, *repr; - char *cname, *crepr; + const char *cname, *crepr; cname = typ->tp_members[i].name; if (cname == NULL) { diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 606e08e449..af09271680 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1624,7 +1624,7 @@ consistent method resolution\norder (MRO) for bases"); i = 0; while (PyDict_Next(set, &i, &k, &v) && (size_t)off < sizeof(buf)) { PyObject *name = class_name(k); - char *name_str; + const char *name_str; if (name != NULL) { name_str = PyUnicode_AsUTF8(name); if (name_str == NULL) @@ -2572,7 +2572,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) PyObject *doc = _PyDict_GetItemId(dict, &PyId___doc__); if (doc != NULL && PyUnicode_Check(doc)) { Py_ssize_t len; - char *doc_str; + const char *doc_str; char *tp_doc; doc_str = PyUnicode_AsUTF8(doc); -- cgit v1.2.1 From ba86008aac6890c5c4a2c6d30ea8110f228d483e Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 20 Nov 2016 12:16:46 +0200 Subject: Issue #19569: Compiler warnings are now emitted if use most of deprecated functions. --- Objects/abstract.c | 28 ++++++++------ Objects/bytearrayobject.c | 5 +-- Objects/bytesobject.c | 5 +-- Objects/codeobject.c | 5 +-- Objects/longobject.c | 2 +- Objects/unicodeobject.c | 94 +++++++++++++++++++++++------------------------ 6 files changed, 67 insertions(+), 72 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index f9afece815..beb12c98f6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -251,14 +251,6 @@ PyObject_DelItemString(PyObject *o, const char *key) /* We release the buffer right after use of this function which could cause issues later on. Don't use these functions in new code. */ -int -PyObject_AsCharBuffer(PyObject *obj, - const char **buffer, - Py_ssize_t *buffer_len) -{ - return PyObject_AsReadBuffer(obj, (const void **)buffer, buffer_len); -} - int PyObject_CheckReadBuffer(PyObject *obj) { @@ -276,9 +268,8 @@ PyObject_CheckReadBuffer(PyObject *obj) return 1; } -int PyObject_AsReadBuffer(PyObject *obj, - const void **buffer, - Py_ssize_t *buffer_len) +static int +as_read_buffer(PyObject *obj, const void **buffer, Py_ssize_t *buffer_len) { Py_buffer view; @@ -295,6 +286,21 @@ int PyObject_AsReadBuffer(PyObject *obj, return 0; } +int +PyObject_AsCharBuffer(PyObject *obj, + const char **buffer, + Py_ssize_t *buffer_len) +{ + return as_read_buffer(obj, (const void **)buffer, buffer_len); +} + +int PyObject_AsReadBuffer(PyObject *obj, + const void **buffer, + Py_ssize_t *buffer_len) +{ + return as_read_buffer(obj, buffer, buffer_len); +} + int PyObject_AsWriteBuffer(PyObject *obj, void **buffer, Py_ssize_t *buffer_len) diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index c6d0707167..16b4fd7a90 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -2324,10 +2324,7 @@ bytearrayiter_reduce(bytesiterobject *it) return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"), it->it_seq, it->it_index); } else { - PyObject *u = PyUnicode_FromUnicode(NULL, 0); - if (u == NULL) - return NULL; - return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), u); + return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter")); } } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 779fe295db..5cdc2ca30e 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3048,10 +3048,7 @@ striter_reduce(striterobject *it) return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"), it->it_seq, it->it_index); } else { - PyObject *u = PyUnicode_FromUnicode(NULL, 0); - if (u == NULL) - return NULL; - return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), u); + return Py_BuildValue("N(())", _PyObject_GetBuiltin("iter")); } } diff --git a/Objects/codeobject.c b/Objects/codeobject.c index f7f91a8168..788818d303 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -115,7 +115,7 @@ PyCode_New(int argcount, int kwonlyargcount, /* Check argument types */ if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 || - code == NULL || + code == NULL || !PyBytes_Check(code) || consts == NULL || !PyTuple_Check(consts) || names == NULL || !PyTuple_Check(names) || varnames == NULL || !PyTuple_Check(varnames) || @@ -123,8 +123,7 @@ PyCode_New(int argcount, int kwonlyargcount, cellvars == NULL || !PyTuple_Check(cellvars) || name == NULL || !PyUnicode_Check(name) || filename == NULL || !PyUnicode_Check(filename) || - lnotab == NULL || !PyBytes_Check(lnotab) || - !PyObject_CheckReadBuffer(code)) { + lnotab == NULL || !PyBytes_Check(lnotab)) { PyErr_BadInternalCall(); return NULL; } diff --git a/Objects/longobject.c b/Objects/longobject.c index 822ed1632f..c95f9467ad 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -2479,7 +2479,7 @@ _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_FromUnicode(u, length); + PyObject *v, *unicode = PyUnicode_FromWideChar(u, length); if (unicode == NULL) return NULL; v = PyLong_FromUnicodeObject(unicode, base); diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 02f726d0ce..0e88fca43f 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -1987,13 +1987,33 @@ unicode_char(Py_UCS4 ch) PyObject * PyUnicode_FromUnicode(const Py_UNICODE *u, Py_ssize_t size) +{ + if (u == NULL) + return (PyObject*)_PyUnicode_New(size); + + if (size < 0) { + PyErr_BadInternalCall(); + return NULL; + } + + return PyUnicode_FromWideChar(u, size); +} + +PyObject * +PyUnicode_FromWideChar(const wchar_t *u, Py_ssize_t size) { PyObject *unicode; Py_UCS4 maxchar = 0; Py_ssize_t num_surrogates; - if (u == NULL) - return (PyObject*)_PyUnicode_New(size); + if (u == NULL && size != 0) { + PyErr_BadInternalCall(); + return NULL; + } + + if (size == -1) { + size = wcslen(u); + } /* If the Unicode data is known at construction time, we can apply some optimizations which share commonly used objects. */ @@ -2478,27 +2498,6 @@ PyUnicode_AsUCS4Copy(PyObject *string) return as_ucs4(string, NULL, 0, 1); } -#ifdef HAVE_WCHAR_H - -PyObject * -PyUnicode_FromWideChar(const wchar_t *w, Py_ssize_t size) -{ - if (w == NULL) { - if (size == 0) - _Py_RETURN_UNICODE_EMPTY(); - PyErr_BadInternalCall(); - return NULL; - } - - if (size == -1) { - size = wcslen(w); - } - - return PyUnicode_FromUnicode(w, size); -} - -#endif /* HAVE_WCHAR_H */ - /* maximum number of characters required for output of %lld or %p. We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits, plus 1 for the sign. 53/22 is an upper bound for log10(256). */ @@ -3296,7 +3295,7 @@ PyUnicode_Encode(const Py_UNICODE *s, { PyObject *v, *unicode; - unicode = PyUnicode_FromUnicode(s, size); + unicode = PyUnicode_FromWideChar(s, size); if (unicode == NULL) return NULL; v = PyUnicode_AsEncodedString(unicode, encoding, errors); @@ -4129,7 +4128,11 @@ PyUnicode_GetSize(PyObject *unicode) PyErr_BadArgument(); goto onError; } - return PyUnicode_GET_SIZE(unicode); + if (_PyUnicode_WSTR(unicode) == NULL) { + if (PyUnicode_AsUnicode(unicode) == NULL) + goto onError; + } + return PyUnicode_WSTR_LENGTH(unicode); onError: return -1; @@ -4815,7 +4818,7 @@ PyUnicode_EncodeUTF7(const Py_UNICODE *s, const char *errors) { PyObject *result; - PyObject *tmp = PyUnicode_FromUnicode(s, size); + PyObject *tmp = PyUnicode_FromWideChar(s, size); if (tmp == NULL) return NULL; result = _PyUnicode_EncodeUTF7(tmp, base64SetO, @@ -5171,7 +5174,7 @@ PyUnicode_EncodeUTF8(const Py_UNICODE *s, { PyObject *v, *unicode; - unicode = PyUnicode_FromUnicode(s, size); + unicode = PyUnicode_FromWideChar(s, size); if (unicode == NULL) return NULL; v = _PyUnicode_AsUTF8String(unicode, errors); @@ -5496,7 +5499,7 @@ PyUnicode_EncodeUTF32(const Py_UNICODE *s, int byteorder) { PyObject *result; - PyObject *tmp = PyUnicode_FromUnicode(s, size); + PyObject *tmp = PyUnicode_FromWideChar(s, size); if (tmp == NULL) return NULL; result = _PyUnicode_EncodeUTF32(tmp, errors, byteorder); @@ -5849,7 +5852,7 @@ PyUnicode_EncodeUTF16(const Py_UNICODE *s, int byteorder) { PyObject *result; - PyObject *tmp = PyUnicode_FromUnicode(s, size); + PyObject *tmp = PyUnicode_FromWideChar(s, size); if (tmp == NULL) return NULL; result = _PyUnicode_EncodeUTF16(tmp, errors, byteorder); @@ -6246,7 +6249,7 @@ PyUnicode_EncodeUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size) { PyObject *result; - PyObject *tmp = PyUnicode_FromUnicode(s, size); + PyObject *tmp = PyUnicode_FromWideChar(s, size); if (tmp == NULL) { return NULL; } @@ -6463,7 +6466,7 @@ PyUnicode_EncodeRawUnicodeEscape(const Py_UNICODE *s, Py_ssize_t size) { PyObject *result; - PyObject *tmp = PyUnicode_FromUnicode(s, size); + PyObject *tmp = PyUnicode_FromWideChar(s, size); if (tmp == NULL) return NULL; result = PyUnicode_AsRawUnicodeEscapeString(tmp); @@ -6874,7 +6877,7 @@ PyUnicode_EncodeLatin1(const Py_UNICODE *p, const char *errors) { PyObject *result; - PyObject *unicode = PyUnicode_FromUnicode(p, size); + PyObject *unicode = PyUnicode_FromWideChar(p, size); if (unicode == NULL) return NULL; result = unicode_encode_ucs1(unicode, errors, 256); @@ -7015,7 +7018,7 @@ PyUnicode_EncodeASCII(const Py_UNICODE *p, const char *errors) { PyObject *result; - PyObject *unicode = PyUnicode_FromUnicode(p, size); + PyObject *unicode = PyUnicode_FromWideChar(p, size); if (unicode == NULL) return NULL; result = unicode_encode_ucs1(unicode, errors, 128); @@ -7741,7 +7744,7 @@ PyUnicode_EncodeMBCS(const Py_UNICODE *p, const char *errors) { PyObject *unicode, *res; - unicode = PyUnicode_FromUnicode(p, size); + unicode = PyUnicode_FromWideChar(p, size); if (unicode == NULL) return NULL; res = encode_code_page(CP_ACP, unicode, errors); @@ -8589,7 +8592,7 @@ PyUnicode_EncodeCharmap(const Py_UNICODE *p, const char *errors) { PyObject *result; - PyObject *unicode = PyUnicode_FromUnicode(p, size); + PyObject *unicode = PyUnicode_FromWideChar(p, size); if (unicode == NULL) return NULL; result = _PyUnicode_EncodeCharmap(unicode, mapping, errors); @@ -9029,7 +9032,7 @@ PyUnicode_TranslateCharmap(const Py_UNICODE *p, const char *errors) { PyObject *result; - PyObject *unicode = PyUnicode_FromUnicode(p, size); + PyObject *unicode = PyUnicode_FromWideChar(p, size); if (!unicode) return NULL; result = _PyUnicode_TranslateCharmap(unicode, mapping, errors); @@ -9157,14 +9160,10 @@ PyUnicode_EncodeDecimal(Py_UNICODE *s, return -1; } - unicode = PyUnicode_FromUnicode(s, length); + unicode = PyUnicode_FromWideChar(s, length); if (unicode == NULL) return -1; - if (PyUnicode_READY(unicode) == -1) { - Py_DECREF(unicode); - return -1; - } kind = PyUnicode_KIND(unicode); data = PyUnicode_DATA(unicode); @@ -15332,7 +15331,7 @@ unicodeiter_reduce(unicodeiterobject *it) return Py_BuildValue("N(O)n", _PyObject_GetBuiltin("iter"), it->it_seq, it->it_index); } else { - PyObject *u = PyUnicode_FromUnicode(NULL, 0); + PyObject *u = (PyObject *)_PyUnicode_New(0); if (u == NULL) return NULL; return Py_BuildValue("N(N)", _PyObject_GetBuiltin("iter"), u); @@ -15427,10 +15426,7 @@ unicode_iter(PyObject *seq) size_t Py_UNICODE_strlen(const Py_UNICODE *u) { - int res = 0; - while(*u++) - res++; - return res; + return wcslen(u); } Py_UNICODE* @@ -15455,8 +15451,8 @@ Py_UNICODE* Py_UNICODE_strcat(Py_UNICODE *s1, const Py_UNICODE *s2) { Py_UNICODE *u1 = s1; - u1 += Py_UNICODE_strlen(u1); - Py_UNICODE_strcpy(u1, s2); + u1 += wcslen(u1); + while ((*u1++ = *s2++)); return s1; } @@ -15505,7 +15501,7 @@ Py_UNICODE* Py_UNICODE_strrchr(const Py_UNICODE *s, Py_UNICODE c) { const Py_UNICODE *p; - p = s + Py_UNICODE_strlen(s); + p = s + wcslen(s); while (p != s) { p--; if (*p == c) -- cgit v1.2.1 From 872753000c7f8c55b0da6316c9c957d909cc95e3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 21 Nov 2016 10:25:54 +0200 Subject: Issue #28748: Private variable _Py_PackageContext is now of type "const char *" rather of "char *". --- Objects/moduleobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 701bcb1df3..350f3bfe3a 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -188,7 +188,7 @@ PyModule_Create2(struct PyModuleDef* module, int module_api_version) (if the name actually matches). */ if (_Py_PackageContext != NULL) { - char *p = strrchr(_Py_PackageContext, '.'); + const char *p = strrchr(_Py_PackageContext, '.'); if (p != NULL && strcmp(module->m_name, p+1) == 0) { name = _Py_PackageContext; _Py_PackageContext = NULL; -- cgit v1.2.1 From a7eaa88fb34028a2928eca85701651703e3047f7 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 22 Nov 2016 00:57:02 +0900 Subject: Issue #28731: Optimize _PyDict_NewPresized() to create correct size dict Improve speed of dict literal with constant keys up to 30%. --- Objects/dictobject.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 320dff6dfc..2a01f70b71 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -389,7 +389,7 @@ dk_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) * This can be used to reserve enough size to insert n entries without * resizing. */ -#define ESTIMATE_SIZE(n) (((n)*3) >> 1) +#define ESTIMATE_SIZE(n) (((n)*3+1) >> 1) /* 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. @@ -1361,12 +1361,26 @@ make_keys_shared(PyObject *op) PyObject * _PyDict_NewPresized(Py_ssize_t minused) { + const Py_ssize_t max_presize = 128 * 1024; Py_ssize_t newsize; PyDictKeysObject *new_keys; - for (newsize = PyDict_MINSIZE; - newsize <= minused && newsize > 0; - newsize <<= 1) - ; + + /* There are no strict guarantee that returned dict can contain minused + * items without resize. So we create medium size dict instead of very + * large dict or MemoryError. + */ + if (minused > USABLE_FRACTION(max_presize)) { + newsize = max_presize; + } + else { + Py_ssize_t minsize = ESTIMATE_SIZE(minused); + newsize = PyDict_MINSIZE; + while (newsize < minsize) { + newsize <<= 1; + } + } + assert(IS_POWER_OF_2(newsize)); + new_keys = new_keys_object(newsize); if (new_keys == NULL) return NULL; -- cgit v1.2.1 From abeacf914be1d289e08cc06be4516e2a7d756032 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 22 Nov 2016 07:58:08 +0200 Subject: Issue #28761: The fields name and doc of structures PyMemberDef, PyGetSetDef, PyStructSequence_Field, PyStructSequence_Desc, and wrapperbase are now of type "const char *" rather of "char *". --- Objects/structseq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/structseq.c b/Objects/structseq.c index 6f1782f29b..c2ece5abb1 100644 --- a/Objects/structseq.c +++ b/Objects/structseq.c @@ -256,7 +256,7 @@ structseq_reduce(PyStructSequence* self) } for (; i < n_fields; i++) { - char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name; + const char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name; if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0) goto error; } -- cgit v1.2.1 From ac89262abd868aed4b06bb0ebf898e97fbab6293 Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Wed, 23 Nov 2016 19:34:01 +0800 Subject: Issue #28774: Fix start/end pos in unicode_encode_ucs1(). Fix error position of the unicode error in ASCII and Latin1 encoders when a string returned by the error handler contains multiple non-encodable characters (non-ASCII for the ASCII codec, characters out of the U+0000-U+00FF range for Latin1). --- Objects/unicodeobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Objects') diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index e88a126eba..2bf48b756f 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -6798,7 +6798,7 @@ unicode_encode_ucs1(PyObject *unicode, goto onError; /* subtract preallocated bytes */ - writer.min_size -= 1; + writer.min_size -= newpos - collstart; if (PyBytes_Check(rep)) { /* Directly copy bytes result to output. */ @@ -6835,7 +6835,7 @@ unicode_encode_ucs1(PyObject *unicode, ch = PyUnicode_READ_CHAR(rep, i); if (ch >= limit) { raise_encode_exception(&exc, encoding, unicode, - pos, pos+1, reason); + collstart, collend, reason); goto onError; } *str = (char)ch; -- cgit v1.2.1 From 2e722071c4726e050d85fd842cd1120288bbbc56 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 23 Nov 2016 15:13:00 +0200 Subject: Issue #28774: Simplified encoding a str result of an error handler in ASCII and Latin1 encoders. --- Objects/unicodeobject.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) (limited to 'Objects') diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 2bf48b756f..1c2257e141 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -6814,33 +6814,19 @@ unicode_encode_ucs1(PyObject *unicode, if (PyUnicode_READY(rep) < 0) goto onError; - if (PyUnicode_IS_ASCII(rep)) { - /* Fast path: all characters are smaller than limit */ - assert(limit >= 128); - assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); - str = _PyBytesWriter_WriteBytes(&writer, str, - PyUnicode_DATA(rep), - PyUnicode_GET_LENGTH(rep)); - } - else { - Py_ssize_t repsize = PyUnicode_GET_LENGTH(rep); - - str = _PyBytesWriter_Prepare(&writer, str, repsize); - if (str == NULL) - goto onError; - - /* check if there is anything unencodable in the - replacement and copy it to the output */ - for (i = 0; repsize-->0; ++i, ++str) { - ch = PyUnicode_READ_CHAR(rep, i); - if (ch >= limit) { - raise_encode_exception(&exc, encoding, unicode, - collstart, collend, reason); - goto onError; - } - *str = (char)ch; - } + if (limit == 256 ? + PyUnicode_KIND(rep) != PyUnicode_1BYTE_KIND : + !PyUnicode_IS_ASCII(rep)) + { + /* Not all characters are smaller than limit */ + raise_encode_exception(&exc, encoding, unicode, + collstart, collend, reason); + goto onError; } + assert(PyUnicode_KIND(rep) == PyUnicode_1BYTE_KIND); + str = _PyBytesWriter_WriteBytes(&writer, str, + PyUnicode_DATA(rep), + PyUnicode_GET_LENGTH(rep)); } pos = newpos; Py_CLEAR(rep); -- cgit v1.2.1 From 7a82fd02f2c897880626cfcd23cf1e1e966138db Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 29 Nov 2016 18:47:56 +0100 Subject: Uniformize argument names of "call" functions * Callable object: callable, o, callable_object => func * Object for method calls: o => obj * Method name: name or nameid => method Cleanup also the C code: * Don't initialize variables to NULL if they are not used before their first assignement * Add braces for readability --- Objects/abstract.c | 122 ++++++++++++++++++++++++++------------------------- Objects/typeobject.c | 17 +++---- 2 files changed, 71 insertions(+), 68 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index beb12c98f6..1a83e93385 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2173,9 +2173,9 @@ PyMapping_Values(PyObject *o) /* XXX PyCallable_Check() is in object.c */ PyObject * -PyObject_CallObject(PyObject *o, PyObject *a) +PyObject_CallObject(PyObject *func, PyObject *args) { - return PyEval_CallObjectWithKeywords(o, a, NULL); + return PyEval_CallObjectWithKeywords(func, args, NULL); } PyObject* @@ -2331,10 +2331,10 @@ exit: return result; } -/* Positional arguments are obj followed args. */ +/* Positional arguments are arg0 followed args: [arg0, *args]. */ PyObject * _PyObject_Call_Prepend(PyObject *func, - PyObject *obj, PyObject *args, PyObject *kwargs) + PyObject *arg0, PyObject *args, PyObject *kwargs) { PyObject *small_stack[8]; PyObject **stack; @@ -2356,7 +2356,7 @@ _PyObject_Call_Prepend(PyObject *func, } /* use borrowed references */ - stack[0] = obj; + stack[0] = arg0; memcpy(&stack[1], &PyTuple_GET_ITEM(args, 0), argcount * sizeof(PyObject *)); @@ -2489,34 +2489,34 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, } static PyObject* -call_function_tail(PyObject *callable, PyObject *args) +call_function_tail(PyObject *func, PyObject *args) { PyObject *result; assert(args != NULL); if (!PyTuple_Check(args)) { - result = _PyObject_CallArg1(callable, args); + result = _PyObject_CallArg1(func, args); } else { - result = PyObject_Call(callable, args, NULL); + result = PyObject_Call(func, args, NULL); } return result; } PyObject * -PyObject_CallFunction(PyObject *callable, const char *format, ...) +PyObject_CallFunction(PyObject *func, const char *format, ...) { va_list va; PyObject *args, *result; - if (callable == NULL) { + if (func == NULL) { return null_error(); } if (!format || !*format) { - return _PyObject_CallNoArg(callable); + return _PyObject_CallNoArg(func); } va_start(va, format); @@ -2526,23 +2526,23 @@ PyObject_CallFunction(PyObject *callable, const char *format, ...) return NULL; } - result = call_function_tail(callable, args); + result = call_function_tail(func, args); Py_DECREF(args); return result; } PyObject * -_PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) +_PyObject_CallFunction_SizeT(PyObject *func, const char *format, ...) { va_list va; PyObject *args, *result; - if (callable == NULL) { + if (func == NULL) { return null_error(); } if (!format || !*format) { - return _PyObject_CallNoArg(callable); + return _PyObject_CallNoArg(func); } va_start(va, format); @@ -2552,7 +2552,7 @@ _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) return NULL; } - result = call_function_tail(callable, args); + result = call_function_tail(func, args); Py_DECREF(args); return result; } @@ -2589,19 +2589,20 @@ callmethod(PyObject* func, const char *format, va_list va, int is_size_t) } PyObject * -PyObject_CallMethod(PyObject *o, const char *name, const char *format, ...) +PyObject_CallMethod(PyObject *obj, const char *method, const char *format, ...) { va_list va; PyObject *func = NULL; PyObject *retval = NULL; - if (o == NULL || name == NULL) { + if (obj == NULL || method == NULL) { return null_error(); } - func = PyObject_GetAttrString(o, name); - if (func == NULL) + func = PyObject_GetAttrString(obj, method); + if (func == NULL) { return NULL; + } va_start(va, format); retval = callmethod(func, format, va, 0); @@ -2611,20 +2612,20 @@ PyObject_CallMethod(PyObject *o, const char *name, const char *format, ...) } PyObject * -_PyObject_CallMethodId(PyObject *o, _Py_Identifier *name, +_PyObject_CallMethodId(PyObject *obj, _Py_Identifier *method, const char *format, ...) { va_list va; - PyObject *func = NULL; - PyObject *retval = NULL; + PyObject *func, *retval; - if (o == NULL || name == NULL) { + if (obj == NULL || method == NULL) { return null_error(); } - func = _PyObject_GetAttrId(o, name); - if (func == NULL) + func = _PyObject_GetAttrId(obj, method); + if (func == NULL) { return NULL; + } va_start(va, format); retval = callmethod(func, format, va, 0); @@ -2634,20 +2635,21 @@ _PyObject_CallMethodId(PyObject *o, _Py_Identifier *name, } PyObject * -_PyObject_CallMethod_SizeT(PyObject *o, const char *name, +_PyObject_CallMethod_SizeT(PyObject *obj, const char *method, const char *format, ...) { va_list va; - PyObject *func = NULL; - PyObject *retval; + PyObject *func, *retval; - if (o == NULL || name == NULL) { + if (obj == NULL || method == NULL) { return null_error(); } - func = PyObject_GetAttrString(o, name); - if (func == NULL) + func = PyObject_GetAttrString(obj, method); + if (func == NULL) { return NULL; + } + va_start(va, format); retval = callmethod(func, format, va, 1); va_end(va); @@ -2656,21 +2658,21 @@ _PyObject_CallMethod_SizeT(PyObject *o, const char *name, } PyObject * -_PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, +_PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *method, const char *format, ...) { va_list va; - PyObject *func = NULL; - PyObject *retval; + PyObject *func, *retval; - if (o == NULL || name == NULL) { + if (obj == NULL || method == NULL) { return null_error(); } - func = _PyObject_GetAttrId(o, name); + func = _PyObject_GetAttrId(obj, method); if (func == NULL) { return NULL; } + va_start(va, format); retval = callmethod(func, format, va, 1); va_end(va); @@ -2720,34 +2722,34 @@ objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, } PyObject * -PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) +PyObject_CallMethodObjArgs(PyObject *obj, PyObject *method, ...) { PyObject *small_stack[5]; PyObject **stack; Py_ssize_t nargs; - PyObject *result; + PyObject *func, *result; va_list vargs; - if (callable == NULL || name == NULL) { + if (obj == NULL || method == NULL) { return null_error(); } - callable = PyObject_GetAttr(callable, name); - if (callable == NULL) + func = PyObject_GetAttr(obj, method); + if (func == NULL) return NULL; /* count the args */ - va_start(vargs, name); + va_start(vargs, method); stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), vargs, &nargs); va_end(vargs); if (stack == NULL) { - Py_DECREF(callable); + Py_DECREF(func); return NULL; } - result = _PyObject_FastCall(callable, stack, nargs); - Py_DECREF(callable); + result = _PyObject_FastCall(func, stack, nargs); + Py_DECREF(func); if (stack != small_stack) { PyMem_Free(stack); } @@ -2756,35 +2758,35 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) } PyObject * -_PyObject_CallMethodIdObjArgs(PyObject *callable, - struct _Py_Identifier *name, ...) +_PyObject_CallMethodIdObjArgs(PyObject *obj, + struct _Py_Identifier *method, ...) { PyObject *small_stack[5]; PyObject **stack; Py_ssize_t nargs; - PyObject *result; + PyObject *func, *result; va_list vargs; - if (callable == NULL || name == NULL) { + if (obj == NULL || method == NULL) { return null_error(); } - callable = _PyObject_GetAttrId(callable, name); - if (callable == NULL) + func = _PyObject_GetAttrId(obj, method); + if (func == NULL) return NULL; /* count the args */ - va_start(vargs, name); + va_start(vargs, method); stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), vargs, &nargs); va_end(vargs); if (stack == NULL) { - Py_DECREF(callable); + Py_DECREF(func); return NULL; } - result = _PyObject_FastCall(callable, stack, nargs); - Py_DECREF(callable); + result = _PyObject_FastCall(func, stack, nargs); + Py_DECREF(func); if (stack != small_stack) { PyMem_Free(stack); } @@ -2793,7 +2795,7 @@ _PyObject_CallMethodIdObjArgs(PyObject *callable, } PyObject * -PyObject_CallFunctionObjArgs(PyObject *callable, ...) +PyObject_CallFunctionObjArgs(PyObject *func, ...) { PyObject *small_stack[5]; PyObject **stack; @@ -2801,12 +2803,12 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...) PyObject *result; va_list vargs; - if (callable == NULL) { + if (func == NULL) { return null_error(); } /* count the args */ - va_start(vargs, callable); + va_start(vargs, func); stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), vargs, &nargs); va_end(vargs); @@ -2814,7 +2816,7 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...) return NULL; } - result = _PyObject_FastCall(callable, stack, nargs); + result = _PyObject_FastCall(func, stack, nargs); if (stack != small_stack) { PyMem_Free(stack); } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 186c57016c..3cff904894 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1425,15 +1425,16 @@ _PyObject_LookupSpecial(PyObject *self, _Py_Identifier *attrid) as lookup_method to cache the interned name string object. */ static PyObject * -call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) +call_method(PyObject *obj, _Py_Identifier *method, const char *format, ...) { va_list va; - PyObject *func = NULL, *retval; + PyObject *func, *retval; - func = lookup_maybe(o, nameid); + func = lookup_maybe(obj, method); if (func == NULL) { - if (!PyErr_Occurred()) - PyErr_SetObject(PyExc_AttributeError, nameid->object); + if (!PyErr_Occurred()) { + PyErr_SetObject(PyExc_AttributeError, method->object); + } return NULL; } @@ -1465,12 +1466,12 @@ call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) /* Clone of call_method() that returns NotImplemented when the lookup fails. */ static PyObject * -call_maybe(PyObject *o, _Py_Identifier *nameid, const char *format, ...) +call_maybe(PyObject *obj, _Py_Identifier *method, const char *format, ...) { va_list va; - PyObject *func = NULL, *retval; + PyObject *func, *retval; - func = lookup_maybe(o, nameid); + func = lookup_maybe(obj, method); if (func == NULL) { if (!PyErr_Occurred()) Py_RETURN_NOTIMPLEMENTED; -- cgit v1.2.1 From cbd0371d81fc46a7a9353ce362ec85ee45ce354b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 30 Nov 2016 12:10:54 +0100 Subject: Backed out changeset 7efddbf1aa70 --- Objects/abstract.c | 122 +++++++++++++++++++++++++-------------------------- Objects/typeobject.c | 17 ++++--- 2 files changed, 68 insertions(+), 71 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 1a83e93385..beb12c98f6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2173,9 +2173,9 @@ PyMapping_Values(PyObject *o) /* XXX PyCallable_Check() is in object.c */ PyObject * -PyObject_CallObject(PyObject *func, PyObject *args) +PyObject_CallObject(PyObject *o, PyObject *a) { - return PyEval_CallObjectWithKeywords(func, args, NULL); + return PyEval_CallObjectWithKeywords(o, a, NULL); } PyObject* @@ -2331,10 +2331,10 @@ exit: return result; } -/* Positional arguments are arg0 followed args: [arg0, *args]. */ +/* Positional arguments are obj followed args. */ PyObject * _PyObject_Call_Prepend(PyObject *func, - PyObject *arg0, PyObject *args, PyObject *kwargs) + PyObject *obj, PyObject *args, PyObject *kwargs) { PyObject *small_stack[8]; PyObject **stack; @@ -2356,7 +2356,7 @@ _PyObject_Call_Prepend(PyObject *func, } /* use borrowed references */ - stack[0] = arg0; + stack[0] = obj; memcpy(&stack[1], &PyTuple_GET_ITEM(args, 0), argcount * sizeof(PyObject *)); @@ -2489,34 +2489,34 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, } static PyObject* -call_function_tail(PyObject *func, PyObject *args) +call_function_tail(PyObject *callable, PyObject *args) { PyObject *result; assert(args != NULL); if (!PyTuple_Check(args)) { - result = _PyObject_CallArg1(func, args); + result = _PyObject_CallArg1(callable, args); } else { - result = PyObject_Call(func, args, NULL); + result = PyObject_Call(callable, args, NULL); } return result; } PyObject * -PyObject_CallFunction(PyObject *func, const char *format, ...) +PyObject_CallFunction(PyObject *callable, const char *format, ...) { va_list va; PyObject *args, *result; - if (func == NULL) { + if (callable == NULL) { return null_error(); } if (!format || !*format) { - return _PyObject_CallNoArg(func); + return _PyObject_CallNoArg(callable); } va_start(va, format); @@ -2526,23 +2526,23 @@ PyObject_CallFunction(PyObject *func, const char *format, ...) return NULL; } - result = call_function_tail(func, args); + result = call_function_tail(callable, args); Py_DECREF(args); return result; } PyObject * -_PyObject_CallFunction_SizeT(PyObject *func, const char *format, ...) +_PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) { va_list va; PyObject *args, *result; - if (func == NULL) { + if (callable == NULL) { return null_error(); } if (!format || !*format) { - return _PyObject_CallNoArg(func); + return _PyObject_CallNoArg(callable); } va_start(va, format); @@ -2552,7 +2552,7 @@ _PyObject_CallFunction_SizeT(PyObject *func, const char *format, ...) return NULL; } - result = call_function_tail(func, args); + result = call_function_tail(callable, args); Py_DECREF(args); return result; } @@ -2589,20 +2589,19 @@ callmethod(PyObject* func, const char *format, va_list va, int is_size_t) } PyObject * -PyObject_CallMethod(PyObject *obj, const char *method, const char *format, ...) +PyObject_CallMethod(PyObject *o, const char *name, const char *format, ...) { va_list va; PyObject *func = NULL; PyObject *retval = NULL; - if (obj == NULL || method == NULL) { + if (o == NULL || name == NULL) { return null_error(); } - func = PyObject_GetAttrString(obj, method); - if (func == NULL) { + func = PyObject_GetAttrString(o, name); + if (func == NULL) return NULL; - } va_start(va, format); retval = callmethod(func, format, va, 0); @@ -2612,20 +2611,20 @@ PyObject_CallMethod(PyObject *obj, const char *method, const char *format, ...) } PyObject * -_PyObject_CallMethodId(PyObject *obj, _Py_Identifier *method, +_PyObject_CallMethodId(PyObject *o, _Py_Identifier *name, const char *format, ...) { va_list va; - PyObject *func, *retval; + PyObject *func = NULL; + PyObject *retval = NULL; - if (obj == NULL || method == NULL) { + if (o == NULL || name == NULL) { return null_error(); } - func = _PyObject_GetAttrId(obj, method); - if (func == NULL) { + func = _PyObject_GetAttrId(o, name); + if (func == NULL) return NULL; - } va_start(va, format); retval = callmethod(func, format, va, 0); @@ -2635,21 +2634,20 @@ _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *method, } PyObject * -_PyObject_CallMethod_SizeT(PyObject *obj, const char *method, +_PyObject_CallMethod_SizeT(PyObject *o, const char *name, const char *format, ...) { va_list va; - PyObject *func, *retval; + PyObject *func = NULL; + PyObject *retval; - if (obj == NULL || method == NULL) { + if (o == NULL || name == NULL) { return null_error(); } - func = PyObject_GetAttrString(obj, method); - if (func == NULL) { + func = PyObject_GetAttrString(o, name); + if (func == NULL) return NULL; - } - va_start(va, format); retval = callmethod(func, format, va, 1); va_end(va); @@ -2658,21 +2656,21 @@ _PyObject_CallMethod_SizeT(PyObject *obj, const char *method, } PyObject * -_PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *method, +_PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, const char *format, ...) { va_list va; - PyObject *func, *retval; + PyObject *func = NULL; + PyObject *retval; - if (obj == NULL || method == NULL) { + if (o == NULL || name == NULL) { return null_error(); } - func = _PyObject_GetAttrId(obj, method); + func = _PyObject_GetAttrId(o, name); if (func == NULL) { return NULL; } - va_start(va, format); retval = callmethod(func, format, va, 1); va_end(va); @@ -2722,34 +2720,34 @@ objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, } PyObject * -PyObject_CallMethodObjArgs(PyObject *obj, PyObject *method, ...) +PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) { PyObject *small_stack[5]; PyObject **stack; Py_ssize_t nargs; - PyObject *func, *result; + PyObject *result; va_list vargs; - if (obj == NULL || method == NULL) { + if (callable == NULL || name == NULL) { return null_error(); } - func = PyObject_GetAttr(obj, method); - if (func == NULL) + callable = PyObject_GetAttr(callable, name); + if (callable == NULL) return NULL; /* count the args */ - va_start(vargs, method); + va_start(vargs, name); stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), vargs, &nargs); va_end(vargs); if (stack == NULL) { - Py_DECREF(func); + Py_DECREF(callable); return NULL; } - result = _PyObject_FastCall(func, stack, nargs); - Py_DECREF(func); + result = _PyObject_FastCall(callable, stack, nargs); + Py_DECREF(callable); if (stack != small_stack) { PyMem_Free(stack); } @@ -2758,35 +2756,35 @@ PyObject_CallMethodObjArgs(PyObject *obj, PyObject *method, ...) } PyObject * -_PyObject_CallMethodIdObjArgs(PyObject *obj, - struct _Py_Identifier *method, ...) +_PyObject_CallMethodIdObjArgs(PyObject *callable, + struct _Py_Identifier *name, ...) { PyObject *small_stack[5]; PyObject **stack; Py_ssize_t nargs; - PyObject *func, *result; + PyObject *result; va_list vargs; - if (obj == NULL || method == NULL) { + if (callable == NULL || name == NULL) { return null_error(); } - func = _PyObject_GetAttrId(obj, method); - if (func == NULL) + callable = _PyObject_GetAttrId(callable, name); + if (callable == NULL) return NULL; /* count the args */ - va_start(vargs, method); + va_start(vargs, name); stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), vargs, &nargs); va_end(vargs); if (stack == NULL) { - Py_DECREF(func); + Py_DECREF(callable); return NULL; } - result = _PyObject_FastCall(func, stack, nargs); - Py_DECREF(func); + result = _PyObject_FastCall(callable, stack, nargs); + Py_DECREF(callable); if (stack != small_stack) { PyMem_Free(stack); } @@ -2795,7 +2793,7 @@ _PyObject_CallMethodIdObjArgs(PyObject *obj, } PyObject * -PyObject_CallFunctionObjArgs(PyObject *func, ...) +PyObject_CallFunctionObjArgs(PyObject *callable, ...) { PyObject *small_stack[5]; PyObject **stack; @@ -2803,12 +2801,12 @@ PyObject_CallFunctionObjArgs(PyObject *func, ...) PyObject *result; va_list vargs; - if (func == NULL) { + if (callable == NULL) { return null_error(); } /* count the args */ - va_start(vargs, func); + va_start(vargs, callable); stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), vargs, &nargs); va_end(vargs); @@ -2816,7 +2814,7 @@ PyObject_CallFunctionObjArgs(PyObject *func, ...) return NULL; } - result = _PyObject_FastCall(func, stack, nargs); + result = _PyObject_FastCall(callable, stack, nargs); if (stack != small_stack) { PyMem_Free(stack); } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 3cff904894..186c57016c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1425,16 +1425,15 @@ _PyObject_LookupSpecial(PyObject *self, _Py_Identifier *attrid) as lookup_method to cache the interned name string object. */ static PyObject * -call_method(PyObject *obj, _Py_Identifier *method, const char *format, ...) +call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) { va_list va; - PyObject *func, *retval; + PyObject *func = NULL, *retval; - func = lookup_maybe(obj, method); + func = lookup_maybe(o, nameid); if (func == NULL) { - if (!PyErr_Occurred()) { - PyErr_SetObject(PyExc_AttributeError, method->object); - } + if (!PyErr_Occurred()) + PyErr_SetObject(PyExc_AttributeError, nameid->object); return NULL; } @@ -1466,12 +1465,12 @@ call_method(PyObject *obj, _Py_Identifier *method, const char *format, ...) /* Clone of call_method() that returns NotImplemented when the lookup fails. */ static PyObject * -call_maybe(PyObject *obj, _Py_Identifier *method, const char *format, ...) +call_maybe(PyObject *o, _Py_Identifier *nameid, const char *format, ...) { va_list va; - PyObject *func, *retval; + PyObject *func = NULL, *retval; - func = lookup_maybe(obj, method); + func = lookup_maybe(o, nameid); if (func == NULL) { if (!PyErr_Occurred()) Py_RETURN_NOTIMPLEMENTED; -- cgit v1.2.1 From 366f4ee4da4420842eac26b3fa00c2b01d4515a6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 1 Dec 2016 14:43:22 +0100 Subject: Replace PyObject_CallFunctionObjArgs() with fastcall * PyObject_CallFunctionObjArgs(func, NULL) => _PyObject_CallNoArg(func) * PyObject_CallFunctionObjArgs(func, arg, NULL) => _PyObject_CallArg1(func, arg) PyObject_CallFunctionObjArgs() allocates 40 bytes on the C stack and requires extra work to "parse" C arguments to build a C array of PyObject*. _PyObject_CallNoArg() and _PyObject_CallArg1() are simpler and don't allocate memory on the C stack. This change is part of the fastcall project. The change on listsort() is related to the issue #23507. --- Objects/abstract.c | 8 ++++---- Objects/bytearrayobject.c | 6 ++---- Objects/bytesobject.c | 7 +++---- Objects/complexobject.c | 2 +- Objects/descrobject.c | 2 +- Objects/dictobject.c | 3 +-- Objects/enumobject.c | 2 +- Objects/floatobject.c | 2 +- Objects/genobject.c | 4 ++-- Objects/listobject.c | 3 +-- Objects/longobject.c | 3 +-- Objects/memoryobject.c | 4 ++-- Objects/object.c | 4 ++-- Objects/odictobject.c | 2 +- Objects/typeobject.c | 6 ++---- Objects/unicodeobject.c | 10 ++++------ Objects/weakrefobject.c | 2 +- 17 files changed, 30 insertions(+), 40 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index beb12c98f6..2f238ed0f1 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -103,7 +103,7 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) } return defaultvalue; } - result = PyObject_CallFunctionObjArgs(hint, NULL); + result = _PyObject_CallNoArg(hint); Py_DECREF(hint); if (result == NULL) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { @@ -716,7 +716,7 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) } /* And call it. */ - result = PyObject_CallFunctionObjArgs(meth, format_spec, NULL); + result = _PyObject_CallArg1(meth, format_spec); Py_DECREF(meth); if (result && !PyUnicode_Check(result)) { @@ -3011,7 +3011,7 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) Py_DECREF(checker); return ok; } - res = PyObject_CallFunctionObjArgs(checker, inst, NULL); + res = _PyObject_CallArg1(checker, inst); Py_LeaveRecursiveCall(); Py_DECREF(checker); if (res != NULL) { @@ -3085,7 +3085,7 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls) Py_DECREF(checker); return ok; } - res = PyObject_CallFunctionObjArgs(checker, derived, NULL); + res = _PyObject_CallArg1(checker, derived); Py_LeaveRecursiveCall(); Py_DECREF(checker); if (res != NULL) { diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 16b4fd7a90..853156eabc 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -98,8 +98,7 @@ _canresize(PyByteArrayObject *self) PyObject * PyByteArray_FromObject(PyObject *input) { - return PyObject_CallFunctionObjArgs((PyObject *)&PyByteArray_Type, - input, NULL); + return _PyObject_CallArg1((PyObject *)&PyByteArray_Type, input); } PyObject * @@ -1985,8 +1984,7 @@ bytearray_fromhex_impl(PyTypeObject *type, PyObject *string) { PyObject *result = _PyBytes_FromHex(string, type == &PyByteArray_Type); if (type != &PyByteArray_Type && result != NULL) { - Py_SETREF(result, PyObject_CallFunctionObjArgs((PyObject *)type, - result, NULL)); + Py_SETREF(result, _PyObject_CallArg1((PyObject *)type, result)); } return result; } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 5cdc2ca30e..b82945ab1d 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -549,7 +549,7 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) /* does it support __bytes__? */ func = _PyObject_LookupSpecial(v, &PyId___bytes__); if (func != NULL) { - result = PyObject_CallFunctionObjArgs(func, NULL); + result = _PyObject_CallNoArg(func); Py_DECREF(func); if (result == NULL) return NULL; @@ -2331,8 +2331,7 @@ bytes_fromhex_impl(PyTypeObject *type, PyObject *string) { PyObject *result = _PyBytes_FromHex(string, 0); if (type != &PyBytes_Type && result != NULL) { - Py_SETREF(result, PyObject_CallFunctionObjArgs((PyObject *)type, - result, NULL)); + Py_SETREF(result, _PyObject_CallArg1((PyObject *)type, result)); } return result; } @@ -2569,7 +2568,7 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyObject_Bytes doesn't do. */ func = _PyObject_LookupSpecial(x, &PyId___bytes__); if (func != NULL) { - new = PyObject_CallFunctionObjArgs(func, NULL); + new = _PyObject_CallNoArg(func); Py_DECREF(func); if (new == NULL) return NULL; diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 31e12784cc..0d391e5208 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -273,7 +273,7 @@ try_complex_special_method(PyObject *op) { f = _PyObject_LookupSpecial(op, &PyId___complex__); if (f) { - PyObject *res = PyObject_CallFunctionObjArgs(f, NULL); + PyObject *res = _PyObject_CallNoArg(f); Py_DECREF(f); if (res != NULL && !PyComplex_Check(res)) { PyErr_SetString(PyExc_TypeError, diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 076e741481..82cc181029 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1414,7 +1414,7 @@ property_descr_set(PyObject *self, PyObject *obj, PyObject *value) return -1; } if (value == NULL) - res = PyObject_CallFunctionObjArgs(func, obj, NULL); + res = _PyObject_CallArg1(func, obj); else res = PyObject_CallFunctionObjArgs(func, obj, value, NULL); if (res == NULL) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 2a01f70b71..b74941ac29 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2066,8 +2066,7 @@ dict_subscript(PyDictObject *mp, PyObject *key) _Py_IDENTIFIER(__missing__); missing = _PyObject_LookupSpecial((PyObject *)mp, &PyId___missing__); if (missing != NULL) { - res = PyObject_CallFunctionObjArgs(missing, - key, NULL); + res = _PyObject_CallArg1(missing, key); Py_DECREF(missing); return res; } diff --git a/Objects/enumobject.c b/Objects/enumobject.c index dae166d5ad..72d31b16af 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -258,7 +258,7 @@ reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } if (reversed_meth != NULL) { - PyObject *res = PyObject_CallFunctionObjArgs(reversed_meth, NULL); + PyObject *res = _PyObject_CallNoArg(reversed_meth); Py_DECREF(reversed_meth); return res; } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 17a55dd114..997d1f9665 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1439,7 +1439,7 @@ float_fromhex(PyObject *cls, PyObject *arg) goto parse_error; result = PyFloat_FromDouble(negate ? -x : x); if (cls != (PyObject *)&PyFloat_Type && result != NULL) { - Py_SETREF(result, PyObject_CallFunctionObjArgs(cls, result, NULL)); + Py_SETREF(result, _PyObject_CallArg1(cls, result)); } return result; diff --git a/Objects/genobject.c b/Objects/genobject.c index 2680ab0e12..1db83c9d64 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -43,7 +43,7 @@ _PyGen_Finalize(PyObject *self) /* Save the current exception, if any. */ PyErr_Fetch(&error_type, &error_value, &error_traceback); - res = PyObject_CallFunctionObjArgs(finalizer, self, NULL); + res = _PyObject_CallArg1(finalizer, self); if (res == NULL) { PyErr_WriteUnraisable(self); @@ -591,7 +591,7 @@ _PyGen_SetStopIterationValue(PyObject *value) * * (See PyErr_SetObject/_PyErr_CreateException code for details.) */ - e = PyObject_CallFunctionObjArgs(PyExc_StopIteration, value, NULL); + e = _PyObject_CallArg1(PyExc_StopIteration, value); if (e == NULL) { return -1; } diff --git a/Objects/listobject.c b/Objects/listobject.c index dcd7b5efe5..81b6c48557 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1970,8 +1970,7 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds) } for (i = 0; i < saved_ob_size ; i++) { - keys[i] = PyObject_CallFunctionObjArgs(keyfunc, saved_ob_item[i], - NULL); + keys[i] = _PyObject_CallArg1(keyfunc, saved_ob_item[i]); if (keys[i] == NULL) { for (i=i-1 ; i>=0 ; i--) Py_DECREF(keys[i]); diff --git a/Objects/longobject.c b/Objects/longobject.c index c95f9467ad..b9f6327759 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5282,8 +5282,7 @@ long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_DECREF(bytes); if (type != &PyLong_Type) { - Py_SETREF(long_obj, PyObject_CallFunctionObjArgs((PyObject *)type, - long_obj, NULL)); + Py_SETREF(long_obj, _PyObject_CallArg1((PyObject *)type, long_obj)); } return long_obj; diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 428d83c987..eac07fbc03 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1939,7 +1939,7 @@ struct_get_unpacker(const char *fmt, Py_ssize_t itemsize) if (format == NULL) goto error; - structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL); + structobj = _PyObject_CallArg1(Struct, format); if (structobj == NULL) goto error; @@ -1978,7 +1978,7 @@ struct_unpack_single(const char *ptr, struct unpacker *x) PyObject *v; memcpy(x->item, ptr, x->itemsize); - v = PyObject_CallFunctionObjArgs(x->unpack_from, x->mview, NULL); + v = _PyObject_CallArg1(x->unpack_from, x->mview); if (v == NULL) return NULL; diff --git a/Objects/object.c b/Objects/object.c index d88ae3b94f..4844bd7669 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -596,7 +596,7 @@ PyObject_Bytes(PyObject *v) func = _PyObject_LookupSpecial(v, &PyId___bytes__); if (func != NULL) { - result = PyObject_CallFunctionObjArgs(func, NULL); + result = _PyObject_CallNoArg(func); Py_DECREF(func); if (result == NULL) return NULL; @@ -1314,7 +1314,7 @@ _dir_object(PyObject *obj) return NULL; } /* use __dir__ */ - result = PyObject_CallFunctionObjArgs(dirfunc, NULL); + result = _PyObject_CallNoArg(dirfunc); Py_DECREF(dirfunc); if (result == NULL) return NULL; diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 22b1f1dfed..77fb3a181d 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1256,7 +1256,7 @@ odict_copy(register PyODictObject *od) if (PyODict_CheckExact(od)) od_copy = PyODict_New(); else - od_copy = PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(od), NULL); + od_copy = _PyObject_CallNoArg((PyObject *)Py_TYPE(od)); if (od_copy == NULL) return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 186c57016c..a9f352046c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3487,9 +3487,7 @@ object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) sorted = _PyDict_GetItemId(builtins, &PyId_sorted); if (sorted == NULL) goto error; - sorted_methods = PyObject_CallFunctionObjArgs(sorted, - abstract_methods, - NULL); + sorted_methods = _PyObject_CallArg1(sorted, abstract_methods); if (sorted_methods == NULL) goto error; comma = _PyUnicode_FromId(&comma_id); @@ -6193,7 +6191,7 @@ call_attribute(PyObject *self, PyObject *attr, PyObject *name) else attr = descr; } - res = PyObject_CallFunctionObjArgs(attr, name, NULL); + res = _PyObject_CallArg1(attr, name); Py_XDECREF(descr); return res; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 1c2257e141..8f6f6c675f 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4269,7 +4269,7 @@ unicode_decode_call_errorhandler_wchar( if (*exceptionObject == NULL) goto onError; - restuple = PyObject_CallFunctionObjArgs(*errorHandler, *exceptionObject, NULL); + restuple = _PyObject_CallArg1(*errorHandler, *exceptionObject); if (restuple == NULL) goto onError; if (!PyTuple_Check(restuple)) { @@ -4368,7 +4368,7 @@ unicode_decode_call_errorhandler_writer( if (*exceptionObject == NULL) goto onError; - restuple = PyObject_CallFunctionObjArgs(*errorHandler, *exceptionObject, NULL); + restuple = _PyObject_CallArg1(*errorHandler, *exceptionObject); if (restuple == NULL) goto onError; if (!PyTuple_Check(restuple)) { @@ -6649,8 +6649,7 @@ unicode_encode_call_errorhandler(const char *errors, if (*exceptionObject == NULL) return NULL; - restuple = PyObject_CallFunctionObjArgs( - *errorHandler, *exceptionObject, NULL); + restuple = _PyObject_CallArg1(*errorHandler, *exceptionObject); if (restuple == NULL) return NULL; if (!PyTuple_Check(restuple)) { @@ -8644,8 +8643,7 @@ unicode_translate_call_errorhandler(const char *errors, if (*exceptionObject == NULL) return NULL; - restuple = PyObject_CallFunctionObjArgs( - *errorHandler, *exceptionObject, NULL); + restuple = _PyObject_CallArg1(*errorHandler, *exceptionObject); if (restuple == NULL) return NULL; if (!PyTuple_Check(restuple)) { diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index ab6b235255..2f33aed026 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -867,7 +867,7 @@ PyWeakref_GetObject(PyObject *ref) static void handle_callback(PyWeakReference *ref, PyObject *callback) { - PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL); + PyObject *cbresult = _PyObject_CallArg1(callback, ref); if (cbresult == NULL) PyErr_WriteUnraisable(callback); -- cgit v1.2.1 From 3f6ef1e99f7c517a21d4f53c63b0aeef7e5b5b2c Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 1 Dec 2016 14:51:04 +0100 Subject: Replace PyObject_CallFunction() with fastcall Replace PyObject_CallFunction(func, "O", arg) and PyObject_CallFunction(func, "O", arg, NULL) with _PyObject_CallArg1(func, arg) Replace PyObject_CallFunction(func, NULL) with _PyObject_CallNoArg(func) _PyObject_CallNoArg() and _PyObject_CallArg1() are simpler and don't allocate memory on the C stack. --- Objects/genobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/genobject.c b/Objects/genobject.c index 1db83c9d64..0484b1c677 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1341,7 +1341,7 @@ async_gen_init_hooks(PyAsyncGenObject *o) PyObject *res; Py_INCREF(firstiter); - res = PyObject_CallFunction(firstiter, "O", o); + res = _PyObject_CallArg1(firstiter, o); Py_DECREF(firstiter); if (res == NULL) { return 1; -- cgit v1.2.1 From 39ae5bedd90f9caf9a78efa82f4d11e838933b3a Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Sun, 4 Dec 2016 22:59:09 +0100 Subject: Backed out changeset b9c9691c72c5 Issue #28858: The change b9c9691c72c5 introduced a regression. It seems like _PyObject_CallArg1() uses more stack memory than PyObject_CallFunctionObjArgs(). --- Objects/abstract.c | 8 ++++---- Objects/bytearrayobject.c | 6 ++++-- Objects/bytesobject.c | 7 ++++--- Objects/complexobject.c | 2 +- Objects/descrobject.c | 2 +- Objects/dictobject.c | 3 ++- Objects/enumobject.c | 2 +- Objects/floatobject.c | 2 +- Objects/genobject.c | 4 ++-- Objects/listobject.c | 3 ++- Objects/longobject.c | 3 ++- Objects/memoryobject.c | 4 ++-- Objects/object.c | 4 ++-- Objects/odictobject.c | 2 +- Objects/typeobject.c | 6 ++++-- Objects/unicodeobject.c | 10 ++++++---- Objects/weakrefobject.c | 2 +- 17 files changed, 40 insertions(+), 30 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 2f238ed0f1..beb12c98f6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -103,7 +103,7 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) } return defaultvalue; } - result = _PyObject_CallNoArg(hint); + result = PyObject_CallFunctionObjArgs(hint, NULL); Py_DECREF(hint); if (result == NULL) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { @@ -716,7 +716,7 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) } /* And call it. */ - result = _PyObject_CallArg1(meth, format_spec); + result = PyObject_CallFunctionObjArgs(meth, format_spec, NULL); Py_DECREF(meth); if (result && !PyUnicode_Check(result)) { @@ -3011,7 +3011,7 @@ PyObject_IsInstance(PyObject *inst, PyObject *cls) Py_DECREF(checker); return ok; } - res = _PyObject_CallArg1(checker, inst); + res = PyObject_CallFunctionObjArgs(checker, inst, NULL); Py_LeaveRecursiveCall(); Py_DECREF(checker); if (res != NULL) { @@ -3085,7 +3085,7 @@ PyObject_IsSubclass(PyObject *derived, PyObject *cls) Py_DECREF(checker); return ok; } - res = _PyObject_CallArg1(checker, derived); + res = PyObject_CallFunctionObjArgs(checker, derived, NULL); Py_LeaveRecursiveCall(); Py_DECREF(checker); if (res != NULL) { diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index 853156eabc..16b4fd7a90 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -98,7 +98,8 @@ _canresize(PyByteArrayObject *self) PyObject * PyByteArray_FromObject(PyObject *input) { - return _PyObject_CallArg1((PyObject *)&PyByteArray_Type, input); + return PyObject_CallFunctionObjArgs((PyObject *)&PyByteArray_Type, + input, NULL); } PyObject * @@ -1984,7 +1985,8 @@ bytearray_fromhex_impl(PyTypeObject *type, PyObject *string) { PyObject *result = _PyBytes_FromHex(string, type == &PyByteArray_Type); if (type != &PyByteArray_Type && result != NULL) { - Py_SETREF(result, _PyObject_CallArg1((PyObject *)type, result)); + Py_SETREF(result, PyObject_CallFunctionObjArgs((PyObject *)type, + result, NULL)); } return result; } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index b82945ab1d..5cdc2ca30e 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -549,7 +549,7 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) /* does it support __bytes__? */ func = _PyObject_LookupSpecial(v, &PyId___bytes__); if (func != NULL) { - result = _PyObject_CallNoArg(func); + result = PyObject_CallFunctionObjArgs(func, NULL); Py_DECREF(func); if (result == NULL) return NULL; @@ -2331,7 +2331,8 @@ bytes_fromhex_impl(PyTypeObject *type, PyObject *string) { PyObject *result = _PyBytes_FromHex(string, 0); if (type != &PyBytes_Type && result != NULL) { - Py_SETREF(result, _PyObject_CallArg1((PyObject *)type, result)); + Py_SETREF(result, PyObject_CallFunctionObjArgs((PyObject *)type, + result, NULL)); } return result; } @@ -2568,7 +2569,7 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyObject_Bytes doesn't do. */ func = _PyObject_LookupSpecial(x, &PyId___bytes__); if (func != NULL) { - new = _PyObject_CallNoArg(func); + new = PyObject_CallFunctionObjArgs(func, NULL); Py_DECREF(func); if (new == NULL) return NULL; diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 0d391e5208..31e12784cc 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -273,7 +273,7 @@ try_complex_special_method(PyObject *op) { f = _PyObject_LookupSpecial(op, &PyId___complex__); if (f) { - PyObject *res = _PyObject_CallNoArg(f); + PyObject *res = PyObject_CallFunctionObjArgs(f, NULL); Py_DECREF(f); if (res != NULL && !PyComplex_Check(res)) { PyErr_SetString(PyExc_TypeError, diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 82cc181029..076e741481 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1414,7 +1414,7 @@ property_descr_set(PyObject *self, PyObject *obj, PyObject *value) return -1; } if (value == NULL) - res = _PyObject_CallArg1(func, obj); + res = PyObject_CallFunctionObjArgs(func, obj, NULL); else res = PyObject_CallFunctionObjArgs(func, obj, value, NULL); if (res == NULL) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index b74941ac29..2a01f70b71 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2066,7 +2066,8 @@ dict_subscript(PyDictObject *mp, PyObject *key) _Py_IDENTIFIER(__missing__); missing = _PyObject_LookupSpecial((PyObject *)mp, &PyId___missing__); if (missing != NULL) { - res = _PyObject_CallArg1(missing, key); + res = PyObject_CallFunctionObjArgs(missing, + key, NULL); Py_DECREF(missing); return res; } diff --git a/Objects/enumobject.c b/Objects/enumobject.c index 72d31b16af..dae166d5ad 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -258,7 +258,7 @@ reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } if (reversed_meth != NULL) { - PyObject *res = _PyObject_CallNoArg(reversed_meth); + PyObject *res = PyObject_CallFunctionObjArgs(reversed_meth, NULL); Py_DECREF(reversed_meth); return res; } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 997d1f9665..17a55dd114 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -1439,7 +1439,7 @@ float_fromhex(PyObject *cls, PyObject *arg) goto parse_error; result = PyFloat_FromDouble(negate ? -x : x); if (cls != (PyObject *)&PyFloat_Type && result != NULL) { - Py_SETREF(result, _PyObject_CallArg1(cls, result)); + Py_SETREF(result, PyObject_CallFunctionObjArgs(cls, result, NULL)); } return result; diff --git a/Objects/genobject.c b/Objects/genobject.c index 0484b1c677..bd7873bceb 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -43,7 +43,7 @@ _PyGen_Finalize(PyObject *self) /* Save the current exception, if any. */ PyErr_Fetch(&error_type, &error_value, &error_traceback); - res = _PyObject_CallArg1(finalizer, self); + res = PyObject_CallFunctionObjArgs(finalizer, self, NULL); if (res == NULL) { PyErr_WriteUnraisable(self); @@ -591,7 +591,7 @@ _PyGen_SetStopIterationValue(PyObject *value) * * (See PyErr_SetObject/_PyErr_CreateException code for details.) */ - e = _PyObject_CallArg1(PyExc_StopIteration, value); + e = PyObject_CallFunctionObjArgs(PyExc_StopIteration, value, NULL); if (e == NULL) { return -1; } diff --git a/Objects/listobject.c b/Objects/listobject.c index 81b6c48557..dcd7b5efe5 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1970,7 +1970,8 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds) } for (i = 0; i < saved_ob_size ; i++) { - keys[i] = _PyObject_CallArg1(keyfunc, saved_ob_item[i]); + keys[i] = PyObject_CallFunctionObjArgs(keyfunc, saved_ob_item[i], + NULL); if (keys[i] == NULL) { for (i=i-1 ; i>=0 ; i--) Py_DECREF(keys[i]); diff --git a/Objects/longobject.c b/Objects/longobject.c index b9f6327759..c95f9467ad 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -5282,7 +5282,8 @@ long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds) Py_DECREF(bytes); if (type != &PyLong_Type) { - Py_SETREF(long_obj, _PyObject_CallArg1((PyObject *)type, long_obj)); + Py_SETREF(long_obj, PyObject_CallFunctionObjArgs((PyObject *)type, + long_obj, NULL)); } return long_obj; diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index eac07fbc03..428d83c987 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1939,7 +1939,7 @@ struct_get_unpacker(const char *fmt, Py_ssize_t itemsize) if (format == NULL) goto error; - structobj = _PyObject_CallArg1(Struct, format); + structobj = PyObject_CallFunctionObjArgs(Struct, format, NULL); if (structobj == NULL) goto error; @@ -1978,7 +1978,7 @@ struct_unpack_single(const char *ptr, struct unpacker *x) PyObject *v; memcpy(x->item, ptr, x->itemsize); - v = _PyObject_CallArg1(x->unpack_from, x->mview); + v = PyObject_CallFunctionObjArgs(x->unpack_from, x->mview, NULL); if (v == NULL) return NULL; diff --git a/Objects/object.c b/Objects/object.c index 4844bd7669..d88ae3b94f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -596,7 +596,7 @@ PyObject_Bytes(PyObject *v) func = _PyObject_LookupSpecial(v, &PyId___bytes__); if (func != NULL) { - result = _PyObject_CallNoArg(func); + result = PyObject_CallFunctionObjArgs(func, NULL); Py_DECREF(func); if (result == NULL) return NULL; @@ -1314,7 +1314,7 @@ _dir_object(PyObject *obj) return NULL; } /* use __dir__ */ - result = _PyObject_CallNoArg(dirfunc); + result = PyObject_CallFunctionObjArgs(dirfunc, NULL); Py_DECREF(dirfunc); if (result == NULL) return NULL; diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 77fb3a181d..22b1f1dfed 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1256,7 +1256,7 @@ odict_copy(register PyODictObject *od) if (PyODict_CheckExact(od)) od_copy = PyODict_New(); else - od_copy = _PyObject_CallNoArg((PyObject *)Py_TYPE(od)); + od_copy = PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(od), NULL); if (od_copy == NULL) return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a9f352046c..186c57016c 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3487,7 +3487,9 @@ object_new(PyTypeObject *type, PyObject *args, PyObject *kwds) sorted = _PyDict_GetItemId(builtins, &PyId_sorted); if (sorted == NULL) goto error; - sorted_methods = _PyObject_CallArg1(sorted, abstract_methods); + sorted_methods = PyObject_CallFunctionObjArgs(sorted, + abstract_methods, + NULL); if (sorted_methods == NULL) goto error; comma = _PyUnicode_FromId(&comma_id); @@ -6191,7 +6193,7 @@ call_attribute(PyObject *self, PyObject *attr, PyObject *name) else attr = descr; } - res = _PyObject_CallArg1(attr, name); + res = PyObject_CallFunctionObjArgs(attr, name, NULL); Py_XDECREF(descr); return res; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 8f6f6c675f..1c2257e141 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -4269,7 +4269,7 @@ unicode_decode_call_errorhandler_wchar( if (*exceptionObject == NULL) goto onError; - restuple = _PyObject_CallArg1(*errorHandler, *exceptionObject); + restuple = PyObject_CallFunctionObjArgs(*errorHandler, *exceptionObject, NULL); if (restuple == NULL) goto onError; if (!PyTuple_Check(restuple)) { @@ -4368,7 +4368,7 @@ unicode_decode_call_errorhandler_writer( if (*exceptionObject == NULL) goto onError; - restuple = _PyObject_CallArg1(*errorHandler, *exceptionObject); + restuple = PyObject_CallFunctionObjArgs(*errorHandler, *exceptionObject, NULL); if (restuple == NULL) goto onError; if (!PyTuple_Check(restuple)) { @@ -6649,7 +6649,8 @@ unicode_encode_call_errorhandler(const char *errors, if (*exceptionObject == NULL) return NULL; - restuple = _PyObject_CallArg1(*errorHandler, *exceptionObject); + restuple = PyObject_CallFunctionObjArgs( + *errorHandler, *exceptionObject, NULL); if (restuple == NULL) return NULL; if (!PyTuple_Check(restuple)) { @@ -8643,7 +8644,8 @@ unicode_translate_call_errorhandler(const char *errors, if (*exceptionObject == NULL) return NULL; - restuple = _PyObject_CallArg1(*errorHandler, *exceptionObject); + restuple = PyObject_CallFunctionObjArgs( + *errorHandler, *exceptionObject, NULL); if (restuple == NULL) return NULL; if (!PyTuple_Check(restuple)) { diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c index 2f33aed026..ab6b235255 100644 --- a/Objects/weakrefobject.c +++ b/Objects/weakrefobject.c @@ -867,7 +867,7 @@ PyWeakref_GetObject(PyObject *ref) static void handle_callback(PyWeakReference *ref, PyObject *callback) { - PyObject *cbresult = _PyObject_CallArg1(callback, ref); + PyObject *cbresult = PyObject_CallFunctionObjArgs(callback, ref, NULL); if (cbresult == NULL) PyErr_WriteUnraisable(callback); -- cgit v1.2.1 From 40273ec4f37c65c13a09d0ac23b08c99ebe2f1a3 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 5 Dec 2016 17:04:32 +0100 Subject: Issue #28858: Remove _PyObject_CallArg1() macro Replace _PyObject_CallArg1(func, arg) with PyObject_CallFunctionObjArgs(func, arg, NULL) Using the _PyObject_CallArg1() macro increases the usage of the C stack, which was unexpected and unwanted. PyObject_CallFunctionObjArgs() doesn't have this issue. --- Objects/abstract.c | 2 +- Objects/fileobject.c | 2 +- Objects/genobject.c | 2 +- Objects/typeobject.c | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index beb12c98f6..a6a58db591 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2496,7 +2496,7 @@ call_function_tail(PyObject *callable, PyObject *args) assert(args != NULL); if (!PyTuple_Check(args)) { - result = _PyObject_CallArg1(callable, args); + result = PyObject_CallFunctionObjArgs(callable, args, NULL); } else { result = PyObject_Call(callable, args, NULL); diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 32f8a8983e..fcdb5fd0a4 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -146,7 +146,7 @@ PyFile_WriteObject(PyObject *v, PyObject *f, int flags) Py_DECREF(writer); return -1; } - result = _PyObject_CallArg1(writer, value); + result = PyObject_CallFunctionObjArgs(writer, value, NULL); Py_DECREF(value); Py_DECREF(writer); if (result == NULL) diff --git a/Objects/genobject.c b/Objects/genobject.c index bd7873bceb..59f53cefcb 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1341,7 +1341,7 @@ async_gen_init_hooks(PyAsyncGenObject *o) PyObject *res; Py_INCREF(firstiter); - res = _PyObject_CallArg1(firstiter, o); + res = PyObject_CallFunctionObjArgs(firstiter, o, NULL); Py_DECREF(firstiter); if (res == NULL) { return 1; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0af153481a..d9699ef1ba 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -5873,7 +5873,7 @@ slot_sq_item(PyObject *self, Py_ssize_t i) goto error; } - retval = _PyObject_CallArg1(func, ival); + retval = PyObject_CallFunctionObjArgs(func, ival, NULL); Py_DECREF(func); Py_DECREF(ival); return retval; @@ -5914,7 +5914,7 @@ slot_sq_contains(PyObject *self, PyObject *value) return -1; } if (func != NULL) { - res = _PyObject_CallArg1(func, value); + res = PyObject_CallFunctionObjArgs(func, value, NULL); Py_DECREF(func); if (res != NULL) { result = PyObject_IsTrue(res); @@ -6284,7 +6284,7 @@ slot_tp_richcompare(PyObject *self, PyObject *other, int op) PyErr_Clear(); Py_RETURN_NOTIMPLEMENTED; } - res = _PyObject_CallArg1(func, other); + res = PyObject_CallFunctionObjArgs(func, other, NULL); Py_DECREF(func); return res; } -- cgit v1.2.1 From 9a6cf6cff587281c54dc45951ff3f24e1385cc18 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 5 Dec 2016 18:23:27 +0100 Subject: Use directly _PyObject_GenericSetAttrWithDict() Modify type_setattro() to call directly _PyObject_GenericSetAttrWithDict() instead of PyObject_GenericSetAttr(). PyObject_GenericSetAttr() is a thin wrapper to _PyObject_GenericSetAttrWithDict(). --- Objects/typeobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index d9699ef1ba..f3e718b5e6 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3082,7 +3082,7 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) type->tp_name); return -1; } - if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0) + if (_PyObject_GenericSetAttrWithDict((PyObject *)type, name, value, NULL) < 0) return -1; return update_slot(type, name); } -- cgit v1.2.1 From 647e75b25047cd0bf6a780e929db7a67de4cca75 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 6 Dec 2016 16:27:24 +0100 Subject: Uniformize argument names of "call" functions Issue #28838: Rename parameters of the "calls" functions of the Python C API. * Rename 'callable_object' and 'func' to 'callable': any Python callable object is accepted, not only Python functions * Rename 'method' and 'nameid' to 'name' (method name) * Rename 'o' to 'obj' * Move, fix and update documentation of PyObject_CallXXX() functions in abstract.h * Update also the documentaton of the C API (update parameter names) --- Objects/abstract.c | 148 +++++++++++++++++++++++++++------------------------ Objects/typeobject.c | 10 ++-- 2 files changed, 83 insertions(+), 75 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index a6a58db591..4cd96368b4 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2173,24 +2173,24 @@ PyMapping_Values(PyObject *o) /* XXX PyCallable_Check() is in object.c */ PyObject * -PyObject_CallObject(PyObject *o, PyObject *a) +PyObject_CallObject(PyObject *callable, PyObject *args) { - return PyEval_CallObjectWithKeywords(o, a, NULL); + return PyEval_CallObjectWithKeywords(callable, args, NULL); } PyObject* -_Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where) +_Py_CheckFunctionResult(PyObject *callable, PyObject *result, const char *where) { int err_occurred = (PyErr_Occurred() != NULL); - assert((func != NULL) ^ (where != NULL)); + assert((callable != NULL) ^ (where != NULL)); if (result == NULL) { if (!err_occurred) { - if (func) + if (callable) PyErr_Format(PyExc_SystemError, "%R returned NULL without setting an error", - func); + callable); else PyErr_Format(PyExc_SystemError, "%s returned NULL without setting an error", @@ -2206,10 +2206,10 @@ _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where) if (err_occurred) { Py_DECREF(result); - if (func) { + if (callable) { _PyErr_FormatFromCause(PyExc_SystemError, "%R returned a result with an error set", - func); + callable); } else { _PyErr_FormatFromCause(PyExc_SystemError, @@ -2227,7 +2227,7 @@ _Py_CheckFunctionResult(PyObject *func, PyObject *result, const char *where) } PyObject * -PyObject_Call(PyObject *func, PyObject *args, PyObject *kwargs) +PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) { ternaryfunc call; PyObject *result; @@ -2239,21 +2239,21 @@ PyObject_Call(PyObject *func, PyObject *args, PyObject *kwargs) assert(PyTuple_Check(args)); assert(kwargs == NULL || PyDict_Check(kwargs)); - call = func->ob_type->tp_call; + call = callable->ob_type->tp_call; if (call == NULL) { PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - func->ob_type->tp_name); + callable->ob_type->tp_name); return NULL; } if (Py_EnterRecursiveCall(" while calling a Python object")) return NULL; - result = (*call)(func, args, kwargs); + result = (*call)(callable, args, kwargs); Py_LeaveRecursiveCall(); - return _Py_CheckFunctionResult(func, result, NULL); + return _Py_CheckFunctionResult(callable, result, NULL); } PyObject* @@ -2277,7 +2277,7 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) } PyObject * -_PyObject_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, +_PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { ternaryfunc call; @@ -2288,7 +2288,7 @@ _PyObject_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, caller loses its exception */ assert(!PyErr_Occurred()); - assert(func != NULL); + assert(callable != NULL); assert(nargs >= 0); assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); @@ -2297,20 +2297,20 @@ _PyObject_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, return NULL; } - if (PyFunction_Check(func)) { - result = _PyFunction_FastCallDict(func, args, nargs, kwargs); + if (PyFunction_Check(callable)) { + result = _PyFunction_FastCallDict(callable, args, nargs, kwargs); } - else if (PyCFunction_Check(func)) { - result = _PyCFunction_FastCallDict(func, args, nargs, kwargs); + else if (PyCFunction_Check(callable)) { + result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs); } else { PyObject *tuple; /* Slow-path: build a temporary tuple */ - call = func->ob_type->tp_call; + call = callable->ob_type->tp_call; if (call == NULL) { PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - func->ob_type->tp_name); + callable->ob_type->tp_name); goto exit; } @@ -2319,10 +2319,10 @@ _PyObject_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, goto exit; } - result = (*call)(func, tuple, kwargs); + result = (*call)(callable, tuple, kwargs); Py_DECREF(tuple); - result = _Py_CheckFunctionResult(func, result, NULL); + result = _Py_CheckFunctionResult(callable, result, NULL); } exit: @@ -2331,9 +2331,10 @@ exit: return result; } -/* Positional arguments are obj followed args. */ +/* Positional arguments are obj followed args: + call callable(obj, *args, **kwargs) */ PyObject * -_PyObject_Call_Prepend(PyObject *func, +_PyObject_Call_Prepend(PyObject *callable, PyObject *obj, PyObject *args, PyObject *kwargs) { PyObject *small_stack[8]; @@ -2361,7 +2362,7 @@ _PyObject_Call_Prepend(PyObject *func, &PyTuple_GET_ITEM(args, 0), argcount * sizeof(PyObject *)); - result = _PyObject_FastCallDict(func, + result = _PyObject_FastCallDict(callable, stack, argcount + 1, kwargs); if (stack != small_stack) { @@ -2452,7 +2453,7 @@ _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, } PyObject * -_PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, +_PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs, PyObject *kwnames) { PyObject *kwdict, *result; @@ -2465,12 +2466,12 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, be unique: these are implemented in Python/ceval.c and _PyArg_ParseStack(). */ - if (PyFunction_Check(func)) { - return _PyFunction_FastCallKeywords(func, stack, nargs, kwnames); + if (PyFunction_Check(callable)) { + return _PyFunction_FastCallKeywords(callable, stack, nargs, kwnames); } - if (PyCFunction_Check(func)) { - return _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames); + if (PyCFunction_Check(callable)) { + return _PyCFunction_FastCallKeywords(callable, stack, nargs, kwnames); } if (nkwargs > 0) { @@ -2483,7 +2484,7 @@ _PyObject_FastCallKeywords(PyObject *func, PyObject **stack, Py_ssize_t nargs, kwdict = NULL; } - result = _PyObject_FastCallDict(func, stack, nargs, kwdict); + result = _PyObject_FastCallDict(callable, stack, nargs, kwdict); Py_XDECREF(kwdict); return result; } @@ -2558,19 +2559,19 @@ _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) } static PyObject* -callmethod(PyObject* func, const char *format, va_list va, int is_size_t) +callmethod(PyObject* callable, const char *format, va_list va, int is_size_t) { PyObject *args, *result; - assert(func != NULL); + assert(callable != NULL); - if (!PyCallable_Check(func)) { - type_error("attribute of type '%.200s' is not callable", func); + if (!PyCallable_Check(callable)) { + type_error("attribute of type '%.200s' is not callable", callable); return NULL; } if (!format || !*format) { - return _PyObject_CallNoArg(func); + return _PyObject_CallNoArg(callable); } if (is_size_t) { @@ -2583,98 +2584,104 @@ callmethod(PyObject* func, const char *format, va_list va, int is_size_t) return NULL; } - result = call_function_tail(func, args); + result = call_function_tail(callable, args); Py_DECREF(args); return result; } PyObject * -PyObject_CallMethod(PyObject *o, const char *name, const char *format, ...) +PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) { va_list va; - PyObject *func = NULL; + PyObject *callable = NULL; PyObject *retval = NULL; - if (o == NULL || name == NULL) { + if (obj == NULL || name == NULL) { return null_error(); } - func = PyObject_GetAttrString(o, name); - if (func == NULL) + callable = PyObject_GetAttrString(obj, name); + if (callable == NULL) return NULL; va_start(va, format); - retval = callmethod(func, format, va, 0); + retval = callmethod(callable, format, va, 0); va_end(va); - Py_DECREF(func); + + Py_DECREF(callable); return retval; } PyObject * -_PyObject_CallMethodId(PyObject *o, _Py_Identifier *name, +_PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, const char *format, ...) { va_list va; - PyObject *func = NULL; + PyObject *callable = NULL; PyObject *retval = NULL; - if (o == NULL || name == NULL) { + if (obj == NULL || name == NULL) { return null_error(); } - func = _PyObject_GetAttrId(o, name); - if (func == NULL) + callable = _PyObject_GetAttrId(obj, name); + if (callable == NULL) return NULL; va_start(va, format); - retval = callmethod(func, format, va, 0); + retval = callmethod(callable, format, va, 0); va_end(va); - Py_DECREF(func); + + Py_DECREF(callable); return retval; } PyObject * -_PyObject_CallMethod_SizeT(PyObject *o, const char *name, +_PyObject_CallMethod_SizeT(PyObject *obj, const char *name, const char *format, ...) { va_list va; - PyObject *func = NULL; + PyObject *callable = NULL; PyObject *retval; - if (o == NULL || name == NULL) { + if (obj == NULL || name == NULL) { return null_error(); } - func = PyObject_GetAttrString(o, name); - if (func == NULL) + callable = PyObject_GetAttrString(obj, name); + if (callable == NULL) return NULL; + va_start(va, format); - retval = callmethod(func, format, va, 1); + retval = callmethod(callable, format, va, 1); va_end(va); - Py_DECREF(func); + + Py_DECREF(callable); return retval; } PyObject * -_PyObject_CallMethodId_SizeT(PyObject *o, _Py_Identifier *name, +_PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, const char *format, ...) { va_list va; - PyObject *func = NULL; + PyObject *callable = NULL; PyObject *retval; - if (o == NULL || name == NULL) { + if (obj == NULL || name == NULL) { return null_error(); } - func = _PyObject_GetAttrId(o, name); - if (func == NULL) { + callable = _PyObject_GetAttrId(obj, name); + if (callable == NULL) { return NULL; } + va_start(va, format); - retval = callmethod(func, format, va, 1); + retval = callmethod(callable, format, va, 1); va_end(va); - Py_DECREF(func); + + Py_DECREF(callable); return retval; } @@ -2756,20 +2763,21 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) } PyObject * -_PyObject_CallMethodIdObjArgs(PyObject *callable, - struct _Py_Identifier *name, ...) +_PyObject_CallMethodIdObjArgs(PyObject *obj, + struct _Py_Identifier *name, ...) { PyObject *small_stack[5]; PyObject **stack; + PyObject *callable; Py_ssize_t nargs; PyObject *result; va_list vargs; - if (callable == NULL || name == NULL) { + if (obj == NULL || name == NULL) { return null_error(); } - callable = _PyObject_GetAttrId(callable, name); + callable = _PyObject_GetAttrId(obj, name); if (callable == NULL) return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f3e718b5e6..0fcdd7d2fc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1425,15 +1425,15 @@ _PyObject_LookupSpecial(PyObject *self, _Py_Identifier *attrid) as lookup_method to cache the interned name string object. */ static PyObject * -call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) +call_method(PyObject *obj, _Py_Identifier *name, const char *format, ...) { va_list va; PyObject *func = NULL, *retval; - func = lookup_maybe(o, nameid); + func = lookup_maybe(obj, name); if (func == NULL) { if (!PyErr_Occurred()) - PyErr_SetObject(PyExc_AttributeError, nameid->object); + PyErr_SetObject(PyExc_AttributeError, name->object); return NULL; } @@ -1465,12 +1465,12 @@ call_method(PyObject *o, _Py_Identifier *nameid, const char *format, ...) /* Clone of call_method() that returns NotImplemented when the lookup fails. */ static PyObject * -call_maybe(PyObject *o, _Py_Identifier *nameid, const char *format, ...) +call_maybe(PyObject *obj, _Py_Identifier *name, const char *format, ...) { va_list va; PyObject *func = NULL, *retval; - func = lookup_maybe(o, nameid); + func = lookup_maybe(obj, name); if (func == NULL) { if (!PyErr_Occurred()) Py_RETURN_NOTIMPLEMENTED; -- cgit v1.2.1 From b729181a504b6aff2461dcbc07c33e902ee90cb0 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 6 Dec 2016 18:45:50 +0100 Subject: Use _PyObject_CallNoArg() Replace: PyObject_CallObject(callable, NULL) with: _PyObject_CallNoArg(callable) --- Objects/dictobject.c | 2 +- Objects/typeobject.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 2a01f70b71..6ec4e0a4a1 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -1843,7 +1843,7 @@ _PyDict_FromKeys(PyObject *cls, PyObject *iterable, PyObject *value) PyObject *d; int status; - d = PyObject_CallObject(cls, NULL); + d = _PyObject_CallNoArg(cls); if (d == NULL) return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0fcdd7d2fc..1758de2032 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1856,7 +1856,7 @@ mro_invoke(PyTypeObject *type) PyObject *mro_meth = lookup_method((PyObject *)type, &PyId_mro); if (mro_meth == NULL) return NULL; - mro_result = PyObject_CallObject(mro_meth, NULL); + mro_result = _PyObject_CallNoArg(mro_meth); Py_DECREF(mro_meth); } else { @@ -4032,7 +4032,7 @@ _PyObject_GetState(PyObject *obj, int required) Py_DECREF(slotnames); } else { /* getstate != NULL */ - state = PyObject_CallObject(getstate, NULL); + state = _PyObject_CallNoArg(getstate); Py_DECREF(getstate); if (state == NULL) return NULL; @@ -4057,7 +4057,7 @@ _PyObject_GetNewArguments(PyObject *obj, PyObject **args, PyObject **kwargs) __getnewargs_ex__ on the object. */ getnewargs_ex = _PyObject_LookupSpecial(obj, &PyId___getnewargs_ex__); if (getnewargs_ex != NULL) { - PyObject *newargs = PyObject_CallObject(getnewargs_ex, NULL); + PyObject *newargs = _PyObject_CallNoArg(getnewargs_ex); Py_DECREF(getnewargs_ex); if (newargs == NULL) { return -1; @@ -4110,7 +4110,7 @@ _PyObject_GetNewArguments(PyObject *obj, PyObject **args, PyObject **kwargs) __getnewargs__ instead. */ getnewargs = _PyObject_LookupSpecial(obj, &PyId___getnewargs__); if (getnewargs != NULL) { - *args = PyObject_CallObject(getnewargs, NULL); + *args = _PyObject_CallNoArg(getnewargs); Py_DECREF(getnewargs); if (*args == NULL) { return -1; @@ -4362,7 +4362,7 @@ object_reduce_ex(PyObject *self, PyObject *args) override = (clsreduce != objreduce); Py_DECREF(clsreduce); if (override) { - res = PyObject_CallObject(reduce, NULL); + res = _PyObject_CallNoArg(reduce); Py_DECREF(reduce); return res; } -- cgit v1.2.1 From a95a307d2cbb7fc1c778691f142e0c21c05fd5bc Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 6 Dec 2016 18:46:19 +0100 Subject: Use _PyObject_CallNoArg() Replace: PyObject_CallFunctionObjArgs(callable, NULL) with: _PyObject_CallNoArg(callable) --- Objects/abstract.c | 2 +- Objects/bytesobject.c | 4 ++-- Objects/complexobject.c | 2 +- Objects/enumobject.c | 2 +- Objects/object.c | 4 ++-- Objects/odictobject.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 4cd96368b4..24948dbfea 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -103,7 +103,7 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) } return defaultvalue; } - result = PyObject_CallFunctionObjArgs(hint, NULL); + result = _PyObject_CallNoArg(hint); Py_DECREF(hint); if (result == NULL) { if (PyErr_ExceptionMatches(PyExc_TypeError)) { diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 5cdc2ca30e..0a5c0ae674 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -549,7 +549,7 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) /* does it support __bytes__? */ func = _PyObject_LookupSpecial(v, &PyId___bytes__); if (func != NULL) { - result = PyObject_CallFunctionObjArgs(func, NULL); + result = _PyObject_CallNoArg(func); Py_DECREF(func); if (result == NULL) return NULL; @@ -2569,7 +2569,7 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyObject_Bytes doesn't do. */ func = _PyObject_LookupSpecial(x, &PyId___bytes__); if (func != NULL) { - new = PyObject_CallFunctionObjArgs(func, NULL); + new = _PyObject_CallNoArg(func); Py_DECREF(func); if (new == NULL) return NULL; diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 31e12784cc..0d391e5208 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -273,7 +273,7 @@ try_complex_special_method(PyObject *op) { f = _PyObject_LookupSpecial(op, &PyId___complex__); if (f) { - PyObject *res = PyObject_CallFunctionObjArgs(f, NULL); + PyObject *res = _PyObject_CallNoArg(f); Py_DECREF(f); if (res != NULL && !PyComplex_Check(res)) { PyErr_SetString(PyExc_TypeError, diff --git a/Objects/enumobject.c b/Objects/enumobject.c index dae166d5ad..72d31b16af 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -258,7 +258,7 @@ reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } if (reversed_meth != NULL) { - PyObject *res = PyObject_CallFunctionObjArgs(reversed_meth, NULL); + PyObject *res = _PyObject_CallNoArg(reversed_meth); Py_DECREF(reversed_meth); return res; } diff --git a/Objects/object.c b/Objects/object.c index d88ae3b94f..4844bd7669 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -596,7 +596,7 @@ PyObject_Bytes(PyObject *v) func = _PyObject_LookupSpecial(v, &PyId___bytes__); if (func != NULL) { - result = PyObject_CallFunctionObjArgs(func, NULL); + result = _PyObject_CallNoArg(func); Py_DECREF(func); if (result == NULL) return NULL; @@ -1314,7 +1314,7 @@ _dir_object(PyObject *obj) return NULL; } /* use __dir__ */ - result = PyObject_CallFunctionObjArgs(dirfunc, NULL); + result = _PyObject_CallNoArg(dirfunc); Py_DECREF(dirfunc); if (result == NULL) return NULL; diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 22b1f1dfed..77fb3a181d 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1256,7 +1256,7 @@ odict_copy(register PyODictObject *od) if (PyODict_CheckExact(od)) od_copy = PyODict_New(); else - od_copy = PyObject_CallFunctionObjArgs((PyObject *)Py_TYPE(od), NULL); + od_copy = _PyObject_CallNoArg((PyObject *)Py_TYPE(od)); if (od_copy == NULL) return NULL; -- cgit v1.2.1 From fe6bb6b27a48ae671bb2c0d888b3e6d3aacce06b Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 6 Dec 2016 18:49:15 +0100 Subject: Fix typo in a comment of abstract.c --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 24948dbfea..034209ccd4 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2463,7 +2463,7 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); assert((nargs == 0 && nkwargs == 0) || stack != NULL); /* kwnames must only contains str strings, no subclass, and all keys must - be unique: these are implemented in Python/ceval.c and + be unique: these checks are implemented in Python/ceval.c and _PyArg_ParseStack(). */ if (PyFunction_Check(callable)) { -- cgit v1.2.1 From 7b1d78db28c9f6983ffe6a4a5600684efd5ca379 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 7 Dec 2016 00:37:38 +0100 Subject: _PyObject_FastCallKeywords() now calls directly tp_call _PyObject_FastCallKeywords() doesn't call _PyObject_FastCallDict() anymore: call directly tp_call. --- Objects/abstract.c | 60 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 15 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 034209ccd4..9b4c124ac3 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2456,12 +2456,9 @@ PyObject * _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs, PyObject *kwnames) { - PyObject *kwdict, *result; - Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - assert(nargs >= 0); assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); + /* kwnames must only contains str strings, no subclass, and all keys must be unique: these checks are implemented in Python/ceval.c and _PyArg_ParseStack(). */ @@ -2469,24 +2466,57 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg if (PyFunction_Check(callable)) { return _PyFunction_FastCallKeywords(callable, stack, nargs, kwnames); } - if (PyCFunction_Check(callable)) { return _PyCFunction_FastCallKeywords(callable, stack, nargs, kwnames); } + else { + /* Slow-path: build a temporary tuple for positional arguments and a + temporary dictionary for keyword arguments (if any) */ - if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, kwnames); - if (kwdict == NULL) { + ternaryfunc call; + PyObject *argtuple; + PyObject *kwdict, *result; + Py_ssize_t nkwargs; + + result = NULL; + nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + assert((nargs == 0 && nkwargs == 0) || stack != NULL); + + if (Py_EnterRecursiveCall(" while calling a Python object")) { return NULL; } - } - else { - kwdict = NULL; - } - result = _PyObject_FastCallDict(callable, stack, nargs, kwdict); - Py_XDECREF(kwdict); - return result; + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + goto exit; + } + + argtuple = _PyStack_AsTuple(stack, nargs); + if (argtuple == NULL) { + goto exit; + } + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(stack + nargs, kwnames); + if (kwdict == NULL) { + Py_DECREF(argtuple); + goto exit; + } + } + else { + kwdict = NULL; + } + + result = (*call)(callable, argtuple, kwdict); + Py_DECREF(argtuple); + Py_XDECREF(kwdict); + + exit: + Py_LeaveRecursiveCall(); + return result; + } } static PyObject* -- cgit v1.2.1 From e5f0c097b310b8aea17164d8851aba4b7571ce49 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Wed, 7 Dec 2016 20:41:42 +0900 Subject: Issue #28818: Simplify lookdict functions --- Objects/dict-common.h | 2 +- Objects/dictobject.c | 216 ++++++++++++++++++++++---------------------------- Objects/odictobject.c | 4 +- 3 files changed, 97 insertions(+), 125 deletions(-) (limited to 'Objects') diff --git a/Objects/dict-common.h b/Objects/dict-common.h index ce9edabd89..6218552734 100644 --- a/Objects/dict-common.h +++ b/Objects/dict-common.h @@ -12,7 +12,7 @@ typedef struct { * -1 when no entry found, -3 when compare raises error. */ typedef Py_ssize_t (*dict_lookup_func) -(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject ***value_addr, +(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos); #define DKIX_EMPTY (-1) diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 6ec4e0a4a1..e7c0db1882 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -223,17 +223,17 @@ equally good collision statistics, needed less code & used less memory. /* forward declarations */ static Py_ssize_t lookdict(PyDictObject *mp, PyObject *key, - Py_hash_t hash, PyObject ***value_addr, + Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos); static Py_ssize_t lookdict_unicode(PyDictObject *mp, PyObject *key, - Py_hash_t hash, PyObject ***value_addr, + Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos); static Py_ssize_t lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, - Py_hash_t hash, PyObject ***value_addr, + Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos); static Py_ssize_t lookdict_split(PyDictObject *mp, PyObject *key, - Py_hash_t hash, PyObject ***value_addr, + Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos); static int dictresize(PyDictObject *mp, Py_ssize_t minused); @@ -685,7 +685,7 @@ where the key index should be inserted. */ static Py_ssize_t _Py_HOT_FUNCTION lookdict(PyDictObject *mp, PyObject *key, - Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) + Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos) { size_t i, mask; Py_ssize_t ix, freeslot; @@ -714,7 +714,7 @@ top: ep = &ep0[ix]; assert(ep->me_key != NULL); if (ep->me_key == key) { - *value_addr = &ep->me_value; + *value_addr = ep->me_value; if (hashpos != NULL) *hashpos = i; return ix; @@ -730,7 +730,7 @@ top: } if (dk == mp->ma_keys && ep->me_key == startkey) { if (cmp > 0) { - *value_addr = &ep->me_value; + *value_addr = ep->me_value; if (hashpos != NULL) *hashpos = i; return ix; @@ -766,7 +766,7 @@ top: if (hashpos != NULL) { *hashpos = i; } - *value_addr = &ep->me_value; + *value_addr = ep->me_value; return ix; } if (ep->me_hash == hash) { @@ -783,7 +783,7 @@ top: if (hashpos != NULL) { *hashpos = i; } - *value_addr = &ep->me_value; + *value_addr = ep->me_value; return ix; } } @@ -800,7 +800,7 @@ top: /* Specialized version for string-only keys */ static Py_ssize_t _Py_HOT_FUNCTION lookdict_unicode(PyDictObject *mp, PyObject *key, - Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) + Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos) { size_t i; size_t mask = DK_MASK(mp->ma_keys); @@ -834,7 +834,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, || (ep->me_hash == hash && unicode_eq(ep->me_key, key))) { if (hashpos != NULL) *hashpos = i; - *value_addr = &ep->me_value; + *value_addr = ep->me_value; return ix; } freeslot = -1; @@ -860,7 +860,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, assert(ep->me_key != NULL); if (ep->me_key == key || (ep->me_hash == hash && unicode_eq(ep->me_key, key))) { - *value_addr = &ep->me_value; + *value_addr = ep->me_value; if (hashpos != NULL) { *hashpos = i; } @@ -875,7 +875,7 @@ lookdict_unicode(PyDictObject *mp, PyObject *key, * will be present. */ static Py_ssize_t _Py_HOT_FUNCTION lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, - Py_hash_t hash, PyObject ***value_addr, + Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos) { size_t i; @@ -908,7 +908,7 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, (ep->me_hash == hash && unicode_eq(ep->me_key, key))) { if (hashpos != NULL) *hashpos = i; - *value_addr = &ep->me_value; + *value_addr = ep->me_value; return ix; } for (size_t perturb = hash;;) { @@ -928,7 +928,7 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, (ep->me_hash == hash && unicode_eq(ep->me_key, key))) { if (hashpos != NULL) *hashpos = i; - *value_addr = &ep->me_value; + *value_addr = ep->me_value; return ix; } } @@ -943,7 +943,7 @@ lookdict_unicode_nodummy(PyDictObject *mp, PyObject *key, */ static Py_ssize_t _Py_HOT_FUNCTION lookdict_split(PyDictObject *mp, PyObject *key, - Py_hash_t hash, PyObject ***value_addr, Py_ssize_t *hashpos) + Py_hash_t hash, PyObject **value_addr, Py_ssize_t *hashpos) { size_t i; size_t mask = DK_MASK(mp->ma_keys); @@ -955,7 +955,7 @@ lookdict_split(PyDictObject *mp, PyObject *key, if (!PyUnicode_CheckExact(key)) { ix = lookdict(mp, key, hash, value_addr, hashpos); if (ix >= 0) { - *value_addr = &mp->ma_values[ix]; + *value_addr = mp->ma_values[ix]; } return ix; } @@ -975,7 +975,7 @@ lookdict_split(PyDictObject *mp, PyObject *key, (ep->me_hash == hash && unicode_eq(ep->me_key, key))) { if (hashpos != NULL) *hashpos = i; - *value_addr = &mp->ma_values[ix]; + *value_addr = mp->ma_values[ix]; return ix; } for (size_t perturb = hash;;) { @@ -995,7 +995,7 @@ lookdict_split(PyDictObject *mp, PyObject *key, (ep->me_hash == hash && unicode_eq(ep->me_key, key))) { if (hashpos != NULL) *hashpos = i; - *value_addr = &mp->ma_values[ix]; + *value_addr = mp->ma_values[ix]; return ix; } } @@ -1068,32 +1068,24 @@ _PyDict_MaybeUntrack(PyObject *op) when it is known that the key is not present in the dict. The dict must be combined. */ -static void -find_empty_slot(PyDictObject *mp, PyObject *key, Py_hash_t hash, - PyObject ***value_addr, Py_ssize_t *hashpos) +static Py_ssize_t +find_empty_slot(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash) { size_t i; - size_t mask = DK_MASK(mp->ma_keys); + size_t mask = DK_MASK(keys); Py_ssize_t ix; - PyDictKeyEntry *ep, *ep0 = DK_ENTRIES(mp->ma_keys); - assert(!_PyDict_HasSplitTable(mp)); - assert(hashpos != NULL); assert(key != NULL); - if (!PyUnicode_CheckExact(key)) - mp->ma_keys->dk_lookup = lookdict; i = hash & mask; - ix = dk_get_index(mp->ma_keys, i); + ix = dk_get_index(keys, i); for (size_t perturb = hash; ix != DKIX_EMPTY;) { perturb >>= PERTURB_SHIFT; i = (i << 2) + i + perturb + 1; - ix = dk_get_index(mp->ma_keys, i & mask); + ix = dk_get_index(keys, i & mask); } - ep = &ep0[mp->ma_keys->dk_nentries]; - *hashpos = i & mask; - assert(ep->me_value == NULL); - *value_addr = &ep->me_value; + assert(DK_ENTRIES(keys)[keys->dk_nentries].me_value == NULL); + return i & mask; } static int @@ -1111,8 +1103,7 @@ static int insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) { PyObject *old_value; - PyObject **value_addr; - PyDictKeyEntry *ep, *ep0; + PyDictKeyEntry *ep; Py_ssize_t hashpos, ix; if (mp->ma_values != NULL && !PyUnicode_CheckExact(key)) { @@ -1120,7 +1111,7 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) return -1; } - ix = mp->ma_keys->dk_lookup(mp, key, hash, &value_addr, &hashpos); + ix = mp->ma_keys->dk_lookup(mp, key, hash, &old_value, &hashpos); if (ix == DKIX_ERROR) { return -1; } @@ -1133,28 +1124,28 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) * the key anymore. Convert this instance to combine table. */ if (_PyDict_HasSplitTable(mp) && - ((ix >= 0 && *value_addr == NULL && mp->ma_used != ix) || + ((ix >= 0 && old_value == NULL && mp->ma_used != ix) || (ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) { if (insertion_resize(mp) < 0) { Py_DECREF(value); return -1; } - find_empty_slot(mp, key, hash, &value_addr, &hashpos); + hashpos = find_empty_slot(mp->ma_keys, key, hash); ix = DKIX_EMPTY; } if (ix == DKIX_EMPTY) { /* Insert into new slot. */ + assert(old_value == NULL); if (mp->ma_keys->dk_usable <= 0) { /* Need to resize. */ if (insertion_resize(mp) < 0) { Py_DECREF(value); return -1; } - find_empty_slot(mp, key, hash, &value_addr, &hashpos); + hashpos = find_empty_slot(mp->ma_keys, key, hash); } - ep0 = DK_ENTRIES(mp->ma_keys); - ep = &ep0[mp->ma_keys->dk_nentries]; + ep = &DK_ENTRIES(mp->ma_keys)[mp->ma_keys->dk_nentries]; dk_set_index(mp->ma_keys, hashpos, mp->ma_keys->dk_nentries); Py_INCREF(key); ep->me_key = key; @@ -1175,24 +1166,21 @@ insertdict(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject *value) return 0; } - assert(value_addr != NULL); - - old_value = *value_addr; - if (old_value != NULL) { - *value_addr = value; - mp->ma_version_tag = DICT_NEXT_VERSION(); - assert(_PyDict_CheckConsistency(mp)); - - Py_DECREF(old_value); /* which **CAN** re-enter (see issue #22653) */ - return 0; + if (_PyDict_HasSplitTable(mp)) { + mp->ma_values[ix] = value; + if (old_value == NULL) { + /* pending state */ + assert(ix == mp->ma_used); + mp->ma_used++; + } + } + else { + assert(old_value != NULL); + DK_ENTRIES(mp->ma_keys)[ix].me_value = value; } - /* pending state */ - assert(_PyDict_HasSplitTable(mp)); - assert(ix == mp->ma_used); - *value_addr = value; - mp->ma_used++; mp->ma_version_tag = DICT_NEXT_VERSION(); + Py_XDECREF(old_value); /* which **CAN** re-enter (see issue #22653) */ assert(_PyDict_CheckConsistency(mp)); return 0; } @@ -1404,7 +1392,7 @@ PyDict_GetItem(PyObject *op, PyObject *key) Py_ssize_t ix; PyDictObject *mp = (PyDictObject *)op; PyThreadState *tstate; - PyObject **value_addr; + PyObject *value; if (!PyDict_Check(op)) return NULL; @@ -1428,20 +1416,20 @@ PyDict_GetItem(PyObject *op, PyObject *key) /* 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_addr, NULL); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); /* ignore errors */ PyErr_Restore(err_type, err_value, err_tb); if (ix < 0) return NULL; } else { - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); if (ix < 0) { PyErr_Clear(); return NULL; } } - return *value_addr; + return value; } /* Same as PyDict_GetItemWithError() but with hash supplied by caller. @@ -1453,18 +1441,18 @@ _PyDict_GetItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) { Py_ssize_t ix; PyDictObject *mp = (PyDictObject *)op; - PyObject **value_addr; + PyObject *value; if (!PyDict_Check(op)) { PyErr_BadInternalCall(); return NULL; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); if (ix < 0) { return NULL; } - return *value_addr; + return value; } /* Variant of PyDict_GetItem() that doesn't suppress exceptions. @@ -1477,7 +1465,7 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key) Py_ssize_t ix; Py_hash_t hash; PyDictObject*mp = (PyDictObject *)op; - PyObject **value_addr; + PyObject *value; if (!PyDict_Check(op)) { PyErr_BadInternalCall(); @@ -1492,10 +1480,10 @@ PyDict_GetItemWithError(PyObject *op, PyObject *key) } } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); if (ix < 0) return NULL; - return *value_addr; + return value; } PyObject * @@ -1520,7 +1508,7 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key) { Py_ssize_t ix; Py_hash_t hash; - PyObject **value_addr; + PyObject *value; if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) @@ -1531,17 +1519,17 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key) } /* namespace 1: globals */ - ix = globals->ma_keys->dk_lookup(globals, key, hash, &value_addr, NULL); + ix = globals->ma_keys->dk_lookup(globals, key, hash, &value, NULL); if (ix == DKIX_ERROR) return NULL; - if (ix != DKIX_EMPTY && *value_addr != NULL) - return *value_addr; + if (ix != DKIX_EMPTY && value != NULL) + return value; /* namespace 2: builtins */ - ix = builtins->ma_keys->dk_lookup(builtins, key, hash, &value_addr, NULL); + ix = builtins->ma_keys->dk_lookup(builtins, key, hash, &value, NULL); if (ix < 0) return NULL; - return *value_addr; + return value; } /* CAUTION: PyDict_SetItem() must guarantee that it won't resize the @@ -1616,7 +1604,6 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) PyDictObject *mp; PyDictKeyEntry *ep; PyObject *old_key, *old_value; - PyObject **value_addr; if (!PyDict_Check(op)) { PyErr_BadInternalCall(); @@ -1625,10 +1612,10 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) assert(key); assert(hash != -1); mp = (PyDictObject *)op; - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); if (ix == DKIX_ERROR) return -1; - if (ix == DKIX_EMPTY || *value_addr == NULL) { + if (ix == DKIX_EMPTY || old_value == NULL) { _PyErr_SetKeyError(key); return -1; } @@ -1639,13 +1626,11 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) if (dictresize(mp, DK_SIZE(mp->ma_keys))) { return -1; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); assert(ix >= 0); } - old_value = *value_addr; assert(old_value != NULL); - *value_addr = NULL; mp->ma_used--; mp->ma_version_tag = DICT_NEXT_VERSION(); ep = &DK_ENTRIES(mp->ma_keys)[ix]; @@ -1653,6 +1638,7 @@ _PyDict_DelItem_KnownHash(PyObject *op, PyObject *key, Py_hash_t hash) ENSURE_ALLOWS_DELETIONS(mp); old_key = ep->me_key; ep->me_key = NULL; + ep->me_value = NULL; Py_DECREF(old_key); Py_DECREF(old_value); @@ -1777,7 +1763,6 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt) Py_ssize_t ix, hashpos; PyObject *old_value, *old_key; PyDictKeyEntry *ep; - PyObject **value_addr; PyDictObject *mp; assert(PyDict_Check(dict)); @@ -1797,10 +1782,10 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt) if (hash == -1) return NULL; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); if (ix == DKIX_ERROR) return NULL; - if (ix == DKIX_EMPTY || *value_addr == NULL) { + if (ix == DKIX_EMPTY || old_value == NULL) { if (deflt) { Py_INCREF(deflt); return deflt; @@ -1814,13 +1799,11 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt) if (dictresize(mp, DK_SIZE(mp->ma_keys))) { return NULL; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &old_value, &hashpos); assert(ix >= 0); } - old_value = *value_addr; assert(old_value != NULL); - *value_addr = NULL; mp->ma_used--; mp->ma_version_tag = DICT_NEXT_VERSION(); dk_set_index(mp->ma_keys, hashpos, DKIX_DUMMY); @@ -1828,6 +1811,7 @@ _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt) ENSURE_ALLOWS_DELETIONS(mp); old_key = ep->me_key; ep->me_key = NULL; + ep->me_value = NULL; Py_DECREF(old_key); assert(_PyDict_CheckConsistency(mp)); @@ -2045,10 +2029,9 @@ dict_length(PyDictObject *mp) static PyObject * dict_subscript(PyDictObject *mp, PyObject *key) { - PyObject *v; Py_ssize_t ix; Py_hash_t hash; - PyObject **value_addr; + PyObject *value; if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { @@ -2056,10 +2039,10 @@ dict_subscript(PyDictObject *mp, PyObject *key) if (hash == -1) return NULL; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); if (ix == DKIX_ERROR) return NULL; - if (ix == DKIX_EMPTY || *value_addr == NULL) { + if (ix == DKIX_EMPTY || value == NULL) { if (!PyDict_CheckExact(mp)) { /* Look up __missing__ method if we're a subclass. */ PyObject *missing, *res; @@ -2077,9 +2060,8 @@ dict_subscript(PyDictObject *mp, PyObject *key) _PyErr_SetKeyError(key); return NULL; } - v = *value_addr; - Py_INCREF(v); - return v; + Py_INCREF(value); + return value; } static int @@ -2651,7 +2633,6 @@ dict_equal(PyDictObject *a, PyDictObject *b) if (aval != NULL) { int cmp; PyObject *bval; - PyObject **vaddr; PyObject *key = ep->me_key; /* temporarily bump aval's refcount to ensure it stays alive until we're done with it */ @@ -2659,10 +2640,7 @@ dict_equal(PyDictObject *a, PyDictObject *b) /* ditto for key */ Py_INCREF(key); /* reuse the known hash value */ - if ((b->ma_keys->dk_lookup)(b, key, ep->me_hash, &vaddr, NULL) < 0) - bval = NULL; - else - bval = *vaddr; + b->ma_keys->dk_lookup(b, key, ep->me_hash, &bval, NULL); Py_DECREF(key); if (bval == NULL) { Py_DECREF(aval); @@ -2718,7 +2696,7 @@ dict___contains__(PyDictObject *self, PyObject *key) register PyDictObject *mp = self; Py_hash_t hash; Py_ssize_t ix; - PyObject **value_addr; + PyObject *value; if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { @@ -2726,10 +2704,10 @@ dict___contains__(PyDictObject *self, PyObject *key) if (hash == -1) return NULL; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); if (ix == DKIX_ERROR) return NULL; - if (ix == DKIX_EMPTY || *value_addr == NULL) + if (ix == DKIX_EMPTY || value == NULL) Py_RETURN_FALSE; Py_RETURN_TRUE; } @@ -2742,7 +2720,6 @@ dict_get(PyDictObject *mp, PyObject *args) PyObject *val = NULL; Py_hash_t hash; Py_ssize_t ix; - PyObject **value_addr; if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj)) return NULL; @@ -2753,13 +2730,12 @@ dict_get(PyDictObject *mp, PyObject *args) if (hash == -1) return NULL; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &val, NULL); if (ix == DKIX_ERROR) return NULL; - if (ix == DKIX_EMPTY || *value_addr == NULL) + if (ix == DKIX_EMPTY || val == NULL) { val = failobj; - else - val = *value_addr; + } Py_INCREF(val); return val; } @@ -2771,7 +2747,6 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) PyObject *value; Py_hash_t hash; Py_ssize_t hashpos, ix; - PyObject **value_addr; if (!PyDict_Check(d)) { PyErr_BadInternalCall(); @@ -2790,17 +2765,17 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) return NULL; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, &hashpos); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, &hashpos); if (ix == DKIX_ERROR) return NULL; if (_PyDict_HasSplitTable(mp) && - ((ix >= 0 && *value_addr == NULL && mp->ma_used != ix) || + ((ix >= 0 && value == NULL && mp->ma_used != ix) || (ix == DKIX_EMPTY && mp->ma_used != mp->ma_keys->dk_nentries))) { if (insertion_resize(mp) < 0) { return NULL; } - find_empty_slot(mp, key, hash, &value_addr, &hashpos); + hashpos = find_empty_slot(mp->ma_keys, key, hash); ix = DKIX_EMPTY; } @@ -2811,7 +2786,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) if (insertion_resize(mp) < 0) { return NULL; } - find_empty_slot(mp, key, hash, &value_addr, &hashpos); + hashpos = find_empty_slot(mp->ma_keys, key, hash); } ep0 = DK_ENTRIES(mp->ma_keys); ep = &ep0[mp->ma_keys->dk_nentries]; @@ -2821,7 +2796,7 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) MAINTAIN_TRACKING(mp, key, value); ep->me_key = key; ep->me_hash = hash; - if (mp->ma_values) { + if (_PyDict_HasSplitTable(mp)) { assert(mp->ma_values[mp->ma_keys->dk_nentries] == NULL); mp->ma_values[mp->ma_keys->dk_nentries] = value; } @@ -2834,19 +2809,16 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) mp->ma_keys->dk_nentries++; assert(mp->ma_keys->dk_usable >= 0); } - else if (*value_addr == NULL) { + else if (value == NULL) { value = defaultobj; assert(_PyDict_HasSplitTable(mp)); assert(ix == mp->ma_used); Py_INCREF(value); MAINTAIN_TRACKING(mp, key, value); - *value_addr = value; + mp->ma_values[ix] = value; mp->ma_used++; mp->ma_version_tag = DICT_NEXT_VERSION(); } - else { - value = *value_addr; - } assert(_PyDict_CheckConsistency(mp)); return value; @@ -3100,7 +3072,7 @@ PyDict_Contains(PyObject *op, PyObject *key) Py_hash_t hash; Py_ssize_t ix; PyDictObject *mp = (PyDictObject *)op; - PyObject **value_addr; + PyObject *value; if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { @@ -3108,10 +3080,10 @@ PyDict_Contains(PyObject *op, PyObject *key) if (hash == -1) return -1; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); if (ix == DKIX_ERROR) return -1; - return (ix != DKIX_EMPTY && *value_addr != NULL); + return (ix != DKIX_EMPTY && value != NULL); } /* Internal version of PyDict_Contains used when the hash value is already known */ @@ -3119,13 +3091,13 @@ int _PyDict_Contains(PyObject *op, PyObject *key, Py_hash_t hash) { PyDictObject *mp = (PyDictObject *)op; - PyObject **value_addr; + PyObject *value; Py_ssize_t ix; - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value_addr, NULL); + ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &value, NULL); if (ix == DKIX_ERROR) return -1; - return (ix != DKIX_EMPTY && *value_addr != NULL); + return (ix != DKIX_EMPTY && value != NULL); } /* Hack to implement "key in dict" */ diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 77fb3a181d..6b33386e17 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -535,11 +535,11 @@ _odict_free_fast_nodes(PyODictObject *od) { static Py_ssize_t _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash) { - PyObject **value_addr = NULL; + PyObject *value = NULL; PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys; Py_ssize_t ix; - ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value_addr, NULL); + ix = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value, NULL); if (ix == DKIX_EMPTY) { return keys->dk_nentries; /* index of new entry */ } -- cgit v1.2.1 From 3eefbce427a8dbc88d9f1bf2490ef97484f63395 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 00:21:55 +0100 Subject: Add _PyObject_FastCallVa() helper Issue #28915: Add _PyObject_FastCallVa() helper to factorize code of functions: * PyObject_CallFunctionObjArgs() * PyObject_CallMethodObjArgs() * _PyObject_CallMethodIdObjArgs() Inline objargs_mkstack() into _PyObject_FastCallVa(), remove objargs_mkstack(). --- Objects/abstract.c | 108 ++++++++++++++++++----------------------------------- 1 file changed, 37 insertions(+), 71 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 9b4c124ac3..b2cf07c08f 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2715,80 +2715,77 @@ _PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, return retval; } -static PyObject ** -objargs_mkstack(PyObject **small_stack, Py_ssize_t small_stack_size, - va_list va, Py_ssize_t *p_nargs) +static PyObject * +_PyObject_FastCallVa(PyObject *callable, va_list vargs) { - Py_ssize_t i, n; - va_list countva; + PyObject *small_stack[5]; PyObject **stack; + Py_ssize_t nargs; + PyObject *result; + Py_ssize_t i; + va_list countva; - /* Count the number of arguments */ - va_copy(countva, va); + if (callable == NULL) { + return null_error(); + } - n = 0; + /* Count the number of arguments */ + va_copy(countva, vargs); + nargs = 0; while (1) { PyObject *arg = va_arg(countva, PyObject *); if (arg == NULL) { break; } - n++; + nargs++; } - *p_nargs = n; + va_end(countva); /* Copy arguments */ - if (n <= small_stack_size) { + if (nargs <= (Py_ssize_t)Py_ARRAY_LENGTH(small_stack)) { stack = small_stack; } else { - stack = PyMem_Malloc(n * sizeof(stack[0])); + stack = PyMem_Malloc(nargs * sizeof(stack[0])); if (stack == NULL) { - va_end(countva); PyErr_NoMemory(); return NULL; } } - for (i = 0; i < n; ++i) { - stack[i] = va_arg(va, PyObject *); + for (i = 0; i < nargs; ++i) { + stack[i] = va_arg(vargs, PyObject *); } - va_end(countva); - return stack; + + /* Call the function */ + result = _PyObject_FastCall(callable, stack, nargs); + + if (stack != small_stack) { + PyMem_Free(stack); + } + return result; } PyObject * PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) { - PyObject *small_stack[5]; - PyObject **stack; - Py_ssize_t nargs; - PyObject *result; va_list vargs; + PyObject *result; if (callable == NULL || name == NULL) { return null_error(); } callable = PyObject_GetAttr(callable, name); - if (callable == NULL) + if (callable == NULL) { return NULL; + } - /* count the args */ va_start(vargs, name); - stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), - vargs, &nargs); + result = _PyObject_FastCallVa(callable, vargs); va_end(vargs); - if (stack == NULL) { - Py_DECREF(callable); - return NULL; - } - result = _PyObject_FastCall(callable, stack, nargs); Py_DECREF(callable); - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; } @@ -2796,66 +2793,35 @@ PyObject * _PyObject_CallMethodIdObjArgs(PyObject *obj, struct _Py_Identifier *name, ...) { - PyObject *small_stack[5]; - PyObject **stack; - PyObject *callable; - Py_ssize_t nargs; - PyObject *result; va_list vargs; + PyObject *callable, *result; if (obj == NULL || name == NULL) { return null_error(); } callable = _PyObject_GetAttrId(obj, name); - if (callable == NULL) + if (callable == NULL) { return NULL; + } - /* count the args */ va_start(vargs, name); - stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), - vargs, &nargs); + result = _PyObject_FastCallVa(callable, vargs); va_end(vargs); - if (stack == NULL) { - Py_DECREF(callable); - return NULL; - } - result = _PyObject_FastCall(callable, stack, nargs); Py_DECREF(callable); - if (stack != small_stack) { - PyMem_Free(stack); - } - return result; } PyObject * PyObject_CallFunctionObjArgs(PyObject *callable, ...) { - PyObject *small_stack[5]; - PyObject **stack; - Py_ssize_t nargs; - PyObject *result; va_list vargs; + PyObject *result; - if (callable == NULL) { - return null_error(); - } - - /* count the args */ va_start(vargs, callable); - stack = objargs_mkstack(small_stack, Py_ARRAY_LENGTH(small_stack), - vargs, &nargs); + result = _PyObject_FastCallVa(callable, vargs); va_end(vargs); - if (stack == NULL) { - return NULL; - } - - result = _PyObject_FastCall(callable, stack, nargs); - if (stack != small_stack) { - PyMem_Free(stack); - } return result; } -- cgit v1.2.1 From 7414b6dc42b094fd694321a85f375ddb4a8c0e19 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 00:22:56 +0100 Subject: Add _PyObject_CallFunctionVa() helper Issue #28915: Add _PyObject_CallFunctionVa() helper to factorize code of functions: * PyObject_CallFunction() * _PyObject_CallFunction_SizeT() * callmethod() --- Objects/abstract.c | 83 +++++++++++++++++++----------------------------------- 1 file changed, 29 insertions(+), 54 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index b2cf07c08f..4f59f04731 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2519,20 +2519,39 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg } } -static PyObject* -call_function_tail(PyObject *callable, PyObject *args) +static PyObject * +_PyObject_CallFunctionVa(PyObject *callable, const char *format, + va_list va, int is_size_t) { - PyObject *result; + PyObject *args, *result; - assert(args != NULL); + if (callable == NULL) { + return null_error(); + } + + if (!format || !*format) { + return _PyObject_CallNoArg(callable); + } + + if (is_size_t) { + args = Py_VaBuildValue(format, va); + } + else { + args = _Py_VaBuildValue_SizeT(format, va); + } + if (args == NULL) { + return NULL; + } if (!PyTuple_Check(args)) { - result = PyObject_CallFunctionObjArgs(callable, args, NULL); + PyObject *stack[1] = {args}; + result = _PyObject_FastCall(callable, stack, 1); } else { result = PyObject_Call(callable, args, NULL); } + Py_DECREF(args); return result; } @@ -2540,25 +2559,12 @@ PyObject * PyObject_CallFunction(PyObject *callable, const char *format, ...) { va_list va; - PyObject *args, *result; - - if (callable == NULL) { - return null_error(); - } - - if (!format || !*format) { - return _PyObject_CallNoArg(callable); - } + PyObject *result; va_start(va, format); - args = Py_VaBuildValue(format, va); + result = _PyObject_CallFunctionVa(callable, format, va, 0); va_end(va); - if (args == NULL) { - return NULL; - } - result = call_function_tail(callable, args); - Py_DECREF(args); return result; } @@ -2566,33 +2572,18 @@ PyObject * _PyObject_CallFunction_SizeT(PyObject *callable, const char *format, ...) { va_list va; - PyObject *args, *result; - - if (callable == NULL) { - return null_error(); - } - - if (!format || !*format) { - return _PyObject_CallNoArg(callable); - } + PyObject *result; va_start(va, format); - args = _Py_VaBuildValue_SizeT(format, va); + result = _PyObject_CallFunctionVa(callable, format, va, 1); va_end(va); - if (args == NULL) { - return NULL; - } - result = call_function_tail(callable, args); - Py_DECREF(args); return result; } static PyObject* callmethod(PyObject* callable, const char *format, va_list va, int is_size_t) { - PyObject *args, *result; - assert(callable != NULL); if (!PyCallable_Check(callable)) { @@ -2600,23 +2591,7 @@ callmethod(PyObject* callable, const char *format, va_list va, int is_size_t) return NULL; } - if (!format || !*format) { - return _PyObject_CallNoArg(callable); - } - - if (is_size_t) { - args = _Py_VaBuildValue_SizeT(format, va); - } - else { - args = Py_VaBuildValue(format, va); - } - if (args == NULL) { - return NULL; - } - - result = call_function_tail(callable, args); - Py_DECREF(args); - return result; + return _PyObject_CallFunctionVa(callable, format, va, is_size_t); } PyObject * -- cgit v1.2.1 From 5524988027d357d99d03c6edf84dcf2216293e75 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 00:31:47 +0100 Subject: _PyObject_CallFunctionVa() uses fast call Issue #28915: Use _Py_VaBuildStack() to build a C array of PyObject* and then use _PyObject_FastCall(). The function has a special case if the stack only contains one parameter and the parameter is a tuple: "unpack" the tuple of arguments in this case. --- Objects/abstract.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 4f59f04731..5c3344cb38 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2523,7 +2523,12 @@ static PyObject * _PyObject_CallFunctionVa(PyObject *callable, const char *format, va_list va, int is_size_t) { - PyObject *args, *result; + PyObject* small_stack[5]; + /*const Py_ssize_t small_stack_len = Py_ARRAY_LENGTH(small_stack);*/ + const Py_ssize_t small_stack_len = 0; + PyObject **stack; + Py_ssize_t nargs, i; + PyObject *result; if (callable == NULL) { return null_error(); @@ -2534,24 +2539,35 @@ _PyObject_CallFunctionVa(PyObject *callable, const char *format, } if (is_size_t) { - args = Py_VaBuildValue(format, va); + stack = _Py_VaBuildStack(small_stack, small_stack_len, format, va, &nargs); } else { - args = _Py_VaBuildValue_SizeT(format, va); + stack = _Py_VaBuildStack_SizeT(small_stack, small_stack_len, format, va, &nargs); } - if (args == NULL) { + if (stack == NULL) { return NULL; } - if (!PyTuple_Check(args)) { - PyObject *stack[1] = {args}; - result = _PyObject_FastCall(callable, stack, 1); + if (nargs == 1 && PyTuple_Check(stack[0])) { + /* Special cases: + - PyObject_CallFunction(func, "O", tuple) calls func(*tuple) + - PyObject_CallFunction(func, "(OOO)", arg1, arg2, arg3) calls + func(*(arg1, arg2, arg3)): func(arg1, arg2, arg3) */ + PyObject *args = stack[0]; + result = _PyObject_FastCall(callable, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args)); } else { - result = PyObject_Call(callable, args, NULL); + result = _PyObject_FastCall(callable, stack, nargs); } - Py_DECREF(args); + for (i = 0; i < nargs; ++i) { + Py_DECREF(stack[i]); + } + if (stack != small_stack) { + PyMem_Free(stack); + } return result; } -- cgit v1.2.1 From ff4988fe1c104125462faa6d68d1f2c957b00727 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 00:36:19 +0100 Subject: Use _PyObject_CallMethodIdObjArgs() Issue #28915: Replace _PyObject_CallMethodId() with _PyObject_CallMethodIdObjArgs() when the format string only use the format 'O' for objects, like "(O)". _PyObject_CallMethodIdObjArgs() avoids the code to parse a format string and avoids the creation of a temporary tuple. --- Objects/descrobject.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 076e741481..ee356b1bf4 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -804,7 +804,8 @@ mappingproxy_get(mappingproxyobject *pp, PyObject *args) if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &def)) return NULL; - return _PyObject_CallMethodId(pp->mapping, &PyId_get, "(OO)", key, def); + return _PyObject_CallMethodIdObjArgs(pp->mapping, &PyId_get, + key, def, NULL); } static PyObject * -- cgit v1.2.1 From cb8c62febe743a22d57f0d431340c0dd8e504fb2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 00:40:33 +0100 Subject: Add _PyObject_VaCallFunctionObjArgs() private function Issue #28915: Similar to _PyObject_CallFunctionObjArgs() but use va_list to pass arguments. --- Objects/abstract.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 5c3344cb38..2c5057d133 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2706,8 +2706,8 @@ _PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, return retval; } -static PyObject * -_PyObject_FastCallVa(PyObject *callable, va_list vargs) +PyObject * +_PyObject_VaCallFunctionObjArgs(PyObject *callable, va_list vargs) { PyObject *small_stack[5]; PyObject **stack; @@ -2773,7 +2773,7 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) } va_start(vargs, name); - result = _PyObject_FastCallVa(callable, vargs); + result = _PyObject_VaCallFunctionObjArgs(callable, vargs); va_end(vargs); Py_DECREF(callable); @@ -2797,7 +2797,7 @@ _PyObject_CallMethodIdObjArgs(PyObject *obj, } va_start(vargs, name); - result = _PyObject_FastCallVa(callable, vargs); + result = _PyObject_VaCallFunctionObjArgs(callable, vargs); va_end(vargs); Py_DECREF(callable); @@ -2811,7 +2811,7 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...) PyObject *result; va_start(vargs, callable); - result = _PyObject_FastCallVa(callable, vargs); + result = _PyObject_VaCallFunctionObjArgs(callable, vargs); va_end(vargs); return result; -- cgit v1.2.1 From 260454930cfe21d8d987c17804740347b4829ee5 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 00:41:46 +0100 Subject: Use _PyObject_FastCallVa() in type slots Issue #28915: Replace Py_VaBuildValue()+PyObject_Call() with _PyObject_FastCallVa() to avoid the creation of temporary tuple. --- Objects/typeobject.c | 131 ++++++++++++++++++++------------------------------- 1 file changed, 50 insertions(+), 81 deletions(-) (limited to 'Objects') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index c7f49b7321..88493b5afc 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1420,15 +1420,15 @@ _PyObject_LookupSpecial(PyObject *self, _Py_Identifier *attrid) return lookup_maybe(self, attrid); } -/* A variation of PyObject_CallMethod that uses lookup_method() +/* A variation of PyObject_CallMethodObjArgs that uses lookup_method() instead of PyObject_GetAttrString(). This uses the same convention as lookup_method to cache the interned name string object. */ static PyObject * -call_method(PyObject *obj, _Py_Identifier *name, const char *format, ...) +call_method(PyObject *obj, _Py_Identifier *name, ...) { va_list va; - PyObject *func = NULL, *retval; + PyObject *func, *retval; func = lookup_maybe(obj, name); if (func == NULL) { @@ -1437,25 +1437,9 @@ call_method(PyObject *obj, _Py_Identifier *name, const char *format, ...) return NULL; } - if (format && *format) { - PyObject *args; - - va_start(va, format); - args = Py_VaBuildValue(format, va); - va_end(va); - - if (args == NULL) { - Py_DECREF(func); - return NULL; - } - assert(PyTuple_Check(args)); - - retval = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } - else { - retval = _PyObject_CallNoArg(func); - } + va_start(va, name); + retval = _PyObject_VaCallFunctionObjArgs(func, va); + va_end(va); Py_DECREF(func); @@ -1465,10 +1449,10 @@ call_method(PyObject *obj, _Py_Identifier *name, const char *format, ...) /* Clone of call_method() that returns NotImplemented when the lookup fails. */ static PyObject * -call_maybe(PyObject *obj, _Py_Identifier *name, const char *format, ...) +call_maybe(PyObject *obj, _Py_Identifier *name, ...) { va_list va; - PyObject *func = NULL, *retval; + PyObject *func, *retval; func = lookup_maybe(obj, name); if (func == NULL) { @@ -1477,25 +1461,9 @@ call_maybe(PyObject *obj, _Py_Identifier *name, const char *format, ...) return NULL; } - if (format && *format) { - PyObject *args; - - va_start(va, format); - args = Py_VaBuildValue(format, va); - va_end(va); - - if (args == NULL) { - Py_DECREF(func); - return NULL; - } - assert(PyTuple_Check(args)); - - retval = PyObject_Call(func, args, NULL); - Py_DECREF(args); - } - else { - retval = _PyObject_CallNoArg(func); - } + va_start(va, name); + retval = _PyObject_VaCallFunctionObjArgs(func, va); + va_end(va); Py_DECREF(func); @@ -5736,12 +5704,12 @@ FUNCNAME(PyObject *self) \ return call_method(self, &id, NULL); \ } -#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE, ARGCODES) \ +#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE) \ static PyObject * \ FUNCNAME(PyObject *self, ARG1TYPE arg1) \ { \ _Py_static_string(id, OPSTR); \ - return call_method(self, &id, "(" ARGCODES ")", arg1); \ + return call_method(self, &id, arg1, NULL); \ } /* Boolean helper for SLOT1BINFULL(). @@ -5794,20 +5762,20 @@ FUNCNAME(PyObject *self, PyObject *other) \ if (do_other && \ PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self)) && \ method_is_overloaded(self, other, &rop_id)) { \ - r = call_maybe(other, &rop_id, "(O)", self); \ + r = call_maybe(other, &rop_id, self, NULL); \ if (r != Py_NotImplemented) \ return r; \ Py_DECREF(r); \ do_other = 0; \ } \ - r = call_maybe(self, &op_id, "(O)", other); \ + r = call_maybe(self, &op_id, other, NULL); \ if (r != Py_NotImplemented || \ Py_TYPE(other) == Py_TYPE(self)) \ return r; \ Py_DECREF(r); \ } \ if (do_other) { \ - return call_maybe(other, &rop_id, "(O)", self); \ + return call_maybe(other, &rop_id, self, NULL); \ } \ Py_RETURN_NOTIMPLEMENTED; \ } @@ -5815,14 +5783,6 @@ FUNCNAME(PyObject *self, PyObject *other) \ #define SLOT1BIN(FUNCNAME, SLOTNAME, OPSTR, ROPSTR) \ SLOT1BINFULL(FUNCNAME, FUNCNAME, SLOTNAME, OPSTR, ROPSTR) -#define SLOT2(FUNCNAME, OPSTR, ARG1TYPE, ARG2TYPE, ARGCODES) \ -static PyObject * \ -FUNCNAME(PyObject *self, ARG1TYPE arg1, ARG2TYPE arg2) \ -{ \ - _Py_static_string(id, #OPSTR); \ - return call_method(self, &id, "(" ARGCODES ")", arg1, arg2); \ -} - static Py_ssize_t slot_sq_length(PyObject *self) { @@ -5887,13 +5847,22 @@ static int slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value) { PyObject *res; + PyObject *index_obj; + + index_obj = PyLong_FromSsize_t(index); + if (index_obj == NULL) { + return -1; + } if (value == NULL) - res = call_method(self, &PyId___delitem__, "(n)", index); + res = call_method(self, &PyId___delitem__, index_obj, NULL); else - res = call_method(self, &PyId___setitem__, "(nO)", index, value); - if (res == NULL) + res = call_method(self, &PyId___setitem__, index_obj, value, NULL); + Py_DECREF(index_obj); + + if (res == NULL) { return -1; + } Py_DECREF(res); return 0; } @@ -5931,7 +5900,7 @@ slot_sq_contains(PyObject *self, PyObject *value) #define slot_mp_length slot_sq_length -SLOT1(slot_mp_subscript, "__getitem__", PyObject *, "O") +SLOT1(slot_mp_subscript, "__getitem__", PyObject *) static int slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value) @@ -5939,9 +5908,9 @@ slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value) PyObject *res; if (value == NULL) - res = call_method(self, &PyId___delitem__, "(O)", key); + res = call_method(self, &PyId___delitem__, key, NULL); else - res = call_method(self, &PyId___setitem__, "(OO)", key, value); + res = call_method(self, &PyId___setitem__, key, value, NULL); if (res == NULL) return -1; @@ -5973,7 +5942,7 @@ slot_nb_power(PyObject *self, PyObject *other, PyObject *modulus) slot_nb_power, so check before calling self.__pow__. */ if (Py_TYPE(self)->tp_as_number != NULL && Py_TYPE(self)->tp_as_number->nb_power == slot_nb_power) { - return call_method(self, &PyId___pow__, "(OO)", other, modulus); + return call_method(self, &PyId___pow__, other, modulus, NULL); } Py_RETURN_NOTIMPLEMENTED; } @@ -6053,28 +6022,28 @@ SLOT1BIN(slot_nb_or, nb_or, "__or__", "__ror__") SLOT0(slot_nb_int, "__int__") SLOT0(slot_nb_float, "__float__") -SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *, "O") -SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *, "O") -SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *, "O") -SLOT1(slot_nb_inplace_matrix_multiply, "__imatmul__", PyObject *, "O") -SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *, "O") +SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *) +SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *) +SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *) +SLOT1(slot_nb_inplace_matrix_multiply, "__imatmul__", PyObject *) +SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *) /* Can't use SLOT1 here, because nb_inplace_power is ternary */ static PyObject * slot_nb_inplace_power(PyObject *self, PyObject * arg1, PyObject *arg2) { _Py_IDENTIFIER(__ipow__); - return call_method(self, &PyId___ipow__, "(" "O" ")", arg1); + return call_method(self, &PyId___ipow__, arg1, NULL); } -SLOT1(slot_nb_inplace_lshift, "__ilshift__", PyObject *, "O") -SLOT1(slot_nb_inplace_rshift, "__irshift__", PyObject *, "O") -SLOT1(slot_nb_inplace_and, "__iand__", PyObject *, "O") -SLOT1(slot_nb_inplace_xor, "__ixor__", PyObject *, "O") -SLOT1(slot_nb_inplace_or, "__ior__", PyObject *, "O") +SLOT1(slot_nb_inplace_lshift, "__ilshift__", PyObject *) +SLOT1(slot_nb_inplace_rshift, "__irshift__", PyObject *) +SLOT1(slot_nb_inplace_and, "__iand__", PyObject *) +SLOT1(slot_nb_inplace_xor, "__ixor__", PyObject *) +SLOT1(slot_nb_inplace_or, "__ior__", PyObject *) SLOT1BIN(slot_nb_floor_divide, nb_floor_divide, "__floordiv__", "__rfloordiv__") SLOT1BIN(slot_nb_true_divide, nb_true_divide, "__truediv__", "__rtruediv__") -SLOT1(slot_nb_inplace_floor_divide, "__ifloordiv__", PyObject *, "O") -SLOT1(slot_nb_inplace_true_divide, "__itruediv__", PyObject *, "O") +SLOT1(slot_nb_inplace_floor_divide, "__ifloordiv__", PyObject *) +SLOT1(slot_nb_inplace_true_divide, "__itruediv__", PyObject *) static PyObject * slot_tp_repr(PyObject *self) @@ -6184,7 +6153,7 @@ slot_tp_call(PyObject *self, PyObject *args, PyObject *kwds) static PyObject * slot_tp_getattro(PyObject *self, PyObject *name) { - return call_method(self, &PyId___getattribute__, "(O)", name); + return call_method(self, &PyId___getattribute__, name, NULL); } static PyObject * @@ -6256,9 +6225,9 @@ slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value) _Py_IDENTIFIER(__setattr__); if (value == NULL) - res = call_method(self, &PyId___delattr__, "(O)", name); + res = call_method(self, &PyId___delattr__, name, NULL); else - res = call_method(self, &PyId___setattr__, "(OO)", name, value); + res = call_method(self, &PyId___setattr__, name, value, NULL); if (res == NULL) return -1; Py_DECREF(res); @@ -6359,9 +6328,9 @@ slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value) _Py_IDENTIFIER(__set__); if (value == NULL) - res = call_method(self, &PyId___delete__, "(O)", target); + res = call_method(self, &PyId___delete__, target, NULL); else - res = call_method(self, &PyId___set__, "(OO)", target, value); + res = call_method(self, &PyId___set__, target, value, NULL); if (res == NULL) return -1; Py_DECREF(res); -- cgit v1.2.1 From 26fbec2e01a2eeac7a59ea585f6fa35e175224de Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 16:22:32 +0100 Subject: Use PyObject_CallFunctionObjArgs() Issue #28915: Replace PyObject_CallFunction() with PyObject_CallFunctionObjArgs() when the format string was only made of "O" formats, PyObject* arguments. PyObject_CallFunctionObjArgs() avoids the creation of a temporary tuple and doesn't have to parse a format string. --- Objects/abstract.c | 2 +- Objects/descrobject.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 2c5057d133..d3b9ec0d19 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2549,7 +2549,7 @@ _PyObject_CallFunctionVa(PyObject *callable, const char *format, } if (nargs == 1 && PyTuple_Check(stack[0])) { - /* Special cases: + /* Special cases for backward compatibility: - PyObject_CallFunction(func, "O", tuple) calls func(*tuple) - PyObject_CallFunction(func, "(OOO)", arg1, arg2, arg3) calls func(*(arg1, arg2, arg3)): func(arg1, arg2, arg3) */ diff --git a/Objects/descrobject.c b/Objects/descrobject.c index ee356b1bf4..090c9cdd04 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1454,7 +1454,7 @@ property_copy(PyObject *old, PyObject *get, PyObject *set, PyObject *del) doc = pold->prop_doc ? pold->prop_doc : Py_None; } - new = PyObject_CallFunction(type, "OOOO", get, set, del, doc); + new = PyObject_CallFunctionObjArgs(type, get, set, del, doc, NULL); Py_DECREF(type); if (new == NULL) return NULL; -- cgit v1.2.1 From 5d3bfadae1b16e75a2e93c0dc7836855b15a1a73 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 17:08:59 +0100 Subject: Remove useless variable initialization Don't initialize variables which are not used before they are assigned. --- Objects/abstract.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index d3b9ec0d19..8892e3ed52 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2614,8 +2614,7 @@ PyObject * PyObject_CallMethod(PyObject *obj, const char *name, const char *format, ...) { va_list va; - PyObject *callable = NULL; - PyObject *retval = NULL; + PyObject *callable, *retval; if (obj == NULL || name == NULL) { return null_error(); @@ -2638,8 +2637,7 @@ _PyObject_CallMethodId(PyObject *obj, _Py_Identifier *name, const char *format, ...) { va_list va; - PyObject *callable = NULL; - PyObject *retval = NULL; + PyObject *callable, *retval; if (obj == NULL || name == NULL) { return null_error(); @@ -2662,8 +2660,7 @@ _PyObject_CallMethod_SizeT(PyObject *obj, const char *name, const char *format, ...) { va_list va; - PyObject *callable = NULL; - PyObject *retval; + PyObject *callable, *retval; if (obj == NULL || name == NULL) { return null_error(); @@ -2686,8 +2683,7 @@ _PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, const char *format, ...) { va_list va; - PyObject *callable = NULL; - PyObject *retval; + PyObject *callable, *retval; if (obj == NULL || name == NULL) { return null_error(); @@ -3112,7 +3108,8 @@ PyObject * PyObject_GetIter(PyObject *o) { PyTypeObject *t = o->ob_type; - getiterfunc f = NULL; + getiterfunc f; + f = t->tp_iter; if (f == NULL) { if (PySequence_Check(o)) -- cgit v1.2.1 From 0a023be4188e0fae813a3a468528452c02f553bb Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 17:12:17 +0100 Subject: Inline PyEval_EvalFrameEx() in callers The PEP 523 modified PyEval_EvalFrameEx(): it's now an indirection to interp->eval_frame(). Inline the call in performance critical code. Leave PyEval_EvalFrame() unchanged, this function is only kept for backward compatibility. --- Objects/genobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/genobject.c b/Objects/genobject.c index 59f53cefcb..9d93a761d7 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -186,7 +186,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) f->f_back = tstate->frame; gen->gi_running = 1; - result = PyEval_EvalFrameEx(f, exc); + result = tstate->interp->eval_frame(f, exc); gen->gi_running = 0; /* Don't keep the reference to f_back any longer than necessary. It -- cgit v1.2.1 From 52f6d966c7b6f06c6b140163799cb809373a53c8 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Fri, 9 Dec 2016 18:51:13 +0100 Subject: Backed out changeset 99c34e47348b The change broke test_gdb. --- Objects/genobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/genobject.c b/Objects/genobject.c index 9d93a761d7..59f53cefcb 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -186,7 +186,7 @@ gen_send_ex(PyGenObject *gen, PyObject *arg, int exc, int closing) f->f_back = tstate->frame; gen->gi_running = 1; - result = tstate->interp->eval_frame(f, exc); + result = PyEval_EvalFrameEx(f, exc); gen->gi_running = 0; /* Don't keep the reference to f_back any longer than necessary. It -- cgit v1.2.1 From 4f5d39b98cc760dcb7641bb71bdaeb2933b1ee40 Mon Sep 17 00:00:00 2001 From: Yury Selivanov Date: Tue, 13 Dec 2016 19:03:51 -0500 Subject: Issue #26110: Add LOAD_METHOD/CALL_METHOD opcodes. Special thanks to INADA Naoki for pushing the patch through the last mile, Serhiy Storchaka for reviewing the code, and to Victor Stinner for suggesting the idea (originally implemented in the PyPy project). --- Objects/object.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/object.c b/Objects/object.c index 4844bd7669..9a7c7f7896 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1025,11 +1025,99 @@ _PyObject_NextNotImplemented(PyObject *self) return NULL; } -/* Generic GetAttr functions - put these in your tp_[gs]etattro slot */ + +/* Specialized version of _PyObject_GenericGetAttrWithDict + specifically for the LOAD_METHOD opcode. + + Return 1 if a method is found, 0 if it's a regular attribute + from __dict__ or something returned by using a descriptor + protocol. + + `method` will point to the resolved attribute or NULL. In the + latter case, an error will be set. +*/ +int +_PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) +{ + PyTypeObject *tp = Py_TYPE(obj); + PyObject *descr; + descrgetfunc f = NULL; + PyObject **dictptr, *dict; + PyObject *attr; + int meth_found = 0; + + assert(*method == NULL); + + if (Py_TYPE(obj)->tp_getattro != PyObject_GenericGetAttr + || !PyUnicode_Check(name)) { + *method = PyObject_GetAttr(obj, name); + return 0; + } + + if (tp->tp_dict == NULL && PyType_Ready(tp) < 0) + return 0; + + descr = _PyType_Lookup(tp, name); + if (descr != NULL) { + Py_INCREF(descr); + if (PyFunction_Check(descr)) { + /* A python method. */ + meth_found = 1; + } else { + f = descr->ob_type->tp_descr_get; + if (f != NULL && PyDescr_IsData(descr)) { + *method = f(descr, obj, (PyObject *)obj->ob_type); + Py_DECREF(descr); + return 0; + } + } + } + + dictptr = _PyObject_GetDictPtr(obj); + if (dictptr != NULL && (dict = *dictptr) != NULL) { + Py_INCREF(dict); + attr = PyDict_GetItem(dict, name); + if (attr != NULL) { + Py_INCREF(attr); + *method = attr; + Py_DECREF(dict); + Py_XDECREF(descr); + return 0; + } + Py_DECREF(dict); + } + + if (meth_found) { + *method = descr; + return 1; + } + + if (f != NULL) { + *method = f(descr, obj, (PyObject *)Py_TYPE(obj)); + Py_DECREF(descr); + return 0; + } + + if (descr != NULL) { + *method = descr; + return 0; + } + + PyErr_Format(PyExc_AttributeError, + "'%.50s' object has no attribute '%U'", + tp->tp_name, name); + return 0; +} + +/* Generic GetAttr functions - put these in your tp_[gs]etattro slot. */ PyObject * _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name, PyObject *dict) { + /* Make sure the logic of _PyObject_GetMethod is in sync with + this method. + */ + PyTypeObject *tp = Py_TYPE(obj); PyObject *descr = NULL; PyObject *res = NULL; -- cgit v1.2.1 From 1e1106c76b9a36dd487704231fde7561a61607d7 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 15 Dec 2016 12:36:50 +0100 Subject: Fix _PyObject_CallFunctionVa(), use the small stack Issue #28915. Oops, I disabled the small stack to test both code paths. It's now fixed. --- Objects/abstract.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 8447fdbc24..7da97ac8a8 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2524,8 +2524,7 @@ _PyObject_CallFunctionVa(PyObject *callable, const char *format, va_list va, int is_size_t) { PyObject* small_stack[5]; - /*const Py_ssize_t small_stack_len = Py_ARRAY_LENGTH(small_stack);*/ - const Py_ssize_t small_stack_len = 0; + const Py_ssize_t small_stack_len = Py_ARRAY_LENGTH(small_stack); PyObject **stack; Py_ssize_t nargs, i; PyObject *result; -- cgit v1.2.1 From cff69a956b4ce78ad7c4318ada06f07959dd8023 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 15 Dec 2016 12:40:53 +0100 Subject: Add _PY_FASTCALL_SMALL_STACK constant Issue #28870: Add a new _PY_FASTCALL_SMALL_STACK constant, size of "small stacks" allocated on the C stack to pass positional arguments to _PyObject_FastCall(). _PyObject_Call_Prepend() now uses a small stack of 5 arguments (40 bytes) instead of 8 (64 bytes), since it is modified to use _PY_FASTCALL_SMALL_STACK. --- Objects/abstract.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 7da97ac8a8..351c6eb56b 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2337,7 +2337,7 @@ PyObject * _PyObject_Call_Prepend(PyObject *callable, PyObject *obj, PyObject *args, PyObject *kwargs) { - PyObject *small_stack[8]; + PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; PyObject **stack; Py_ssize_t argcount; PyObject *result; @@ -2523,7 +2523,7 @@ static PyObject * _PyObject_CallFunctionVa(PyObject *callable, const char *format, va_list va, int is_size_t) { - PyObject* small_stack[5]; + PyObject* small_stack[_PY_FASTCALL_SMALL_STACK]; const Py_ssize_t small_stack_len = Py_ARRAY_LENGTH(small_stack); PyObject **stack; Py_ssize_t nargs, i; @@ -2704,7 +2704,7 @@ _PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, PyObject * _PyObject_VaCallFunctionObjArgs(PyObject *callable, va_list vargs) { - PyObject *small_stack[5]; + PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; PyObject **stack; Py_ssize_t nargs; PyObject *result; -- cgit v1.2.1 From 15f6772cc70245d61451cf16f64da47b36389c67 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 15 Dec 2016 16:59:40 +0100 Subject: Use _PyDict_NewPresized() in _PyStack_AsDict() Issue #27810. --- Objects/abstract.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 351c6eb56b..67b163d7b7 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2378,7 +2378,7 @@ _PyStack_AsDict(PyObject **values, PyObject *kwnames) PyObject *kwdict; Py_ssize_t i; - kwdict = PyDict_New(); + kwdict = _PyDict_NewPresized(nkwargs); if (kwdict == NULL) { return NULL; } -- cgit v1.2.1 From f22b56b777f7134b5c4e6c9caa9249e92c4f4fd9 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 16 Dec 2016 16:18:57 +0200 Subject: Issue #28959: Added private macro PyDict_GET_SIZE for retrieving the size of dict. --- Objects/abstract.c | 3 +-- Objects/descrobject.c | 2 +- Objects/funcobject.c | 2 +- Objects/methodobject.c | 9 +++++---- Objects/object.c | 4 ++-- Objects/odictobject.c | 3 +-- Objects/setobject.c | 2 +- Objects/sliceobject.c | 2 +- Objects/typeobject.c | 16 ++++++++-------- 9 files changed, 21 insertions(+), 22 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 67b163d7b7..8d1eddc093 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2409,8 +2409,7 @@ _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, assert(nargs >= 0); assert(kwargs == NULL || PyDict_CheckExact(kwargs)); - nkwargs = (kwargs != NULL) ? PyDict_Size(kwargs) : 0; - if (!nkwargs) { + if (kwargs == NULL || (nkwargs = PyDict_GET_SIZE(kwargs)) == 0) { *p_kwnames = NULL; return args; } diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 090c9cdd04..ed398919a3 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -1173,7 +1173,7 @@ wrapper_call(wrapperobject *wp, PyObject *args, PyObject *kwds) return (*wk)(self, args, wp->descr->d_wrapped, kwds); } - if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_Size(kwds) != 0)) { + if (kwds != NULL && (!PyDict_Check(kwds) || PyDict_GET_SIZE(kwds) != 0)) { PyErr_Format(PyExc_TypeError, "wrapper %s doesn't take keyword arguments", wp->descr->d_base->name); diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 69cd973384..63aa9de583 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -583,7 +583,7 @@ function_call(PyObject *func, PyObject *arg, PyObject *kw) if (kw != NULL && PyDict_Check(kw)) { Py_ssize_t pos, i; - nk = PyDict_Size(kw); + nk = PyDict_GET_SIZE(kw); kwtuple = PyTuple_New(2*nk); if (kwtuple == NULL) return NULL; diff --git a/Objects/methodobject.c b/Objects/methodobject.c index c2001f0169..14750b6318 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -87,6 +87,7 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) Py_ssize_t size; int flags; + assert(kwds == NULL || PyDict_Check(kwds)); /* PyCFunction_Call() must not be called with an exception set, because it may clear it (directly or indirectly) and so the caller loses its exception */ @@ -103,7 +104,7 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) res = _PyCFunction_FastCallDict(func, stack, nargs, kwds); } else { - if (kwds != NULL && PyDict_Size(kwds) != 0) { + if (kwds != NULL && PyDict_GET_SIZE(kwds) != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", f->m_ml->ml_name); return NULL; @@ -176,7 +177,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, switch (flags) { case METH_NOARGS: - if (kwargs != NULL && PyDict_Size(kwargs) != 0) { + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", func->m_ml->ml_name); return NULL; @@ -193,7 +194,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, break; case METH_O: - if (kwargs != NULL && PyDict_Size(kwargs) != 0) { + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", func->m_ml->ml_name); return NULL; @@ -215,7 +216,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, /* Slow-path: create a temporary tuple */ PyObject *tuple; - if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_Size(kwargs) != 0) { + if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", func->m_ml->ml_name); diff --git a/Objects/object.c b/Objects/object.c index 9a7c7f7896..dc50131e3f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1454,7 +1454,7 @@ none_dealloc(PyObject* ignore) static PyObject * none_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_Size(kwargs))) { + if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) { PyErr_SetString(PyExc_TypeError, "NoneType takes no arguments"); return NULL; } @@ -1573,7 +1573,7 @@ static PyMethodDef notimplemented_methods[] = { static PyObject * notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_Size(kwargs))) { + if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) { PyErr_SetString(PyExc_TypeError, "NotImplementedType takes no arguments"); return NULL; } diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 6b33386e17..8e6d643e90 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -2423,8 +2423,7 @@ mutablemapping_update(PyObject *self, PyObject *args, PyObject *kwargs) /* now handle kwargs */ assert(kwargs == NULL || PyDict_Check(kwargs)); - len = (kwargs != NULL) ? PyDict_Size(kwargs) : 0; - if (len > 0) { + if (kwargs != NULL && PyDict_GET_SIZE(kwargs)) { PyObject *items = PyDict_Items(kwargs); if (items == NULL) return NULL; diff --git a/Objects/setobject.c b/Objects/setobject.c index b7e0617db3..59ed7955e6 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -981,7 +981,7 @@ set_update_internal(PySetObject *so, PyObject *other) PyObject *value; Py_ssize_t pos = 0; Py_hash_t hash; - Py_ssize_t dictsize = PyDict_Size(other); + Py_ssize_t dictsize = PyDict_GET_SIZE(other); /* Do one big resize at the start, rather than * incrementally resizing as we insert new keys. Expect diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index 2f32355cd2..1dc7e4e656 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -19,7 +19,7 @@ this type and there is exactly one in existence. static PyObject * ellipsis_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { - if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_Size(kwargs))) { + if (PyTuple_GET_SIZE(args) || (kwargs && PyDict_GET_SIZE(kwargs))) { PyErr_SetString(PyExc_TypeError, "EllipsisType takes no arguments"); return NULL; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 391eed3156..37f0082587 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -902,7 +902,7 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) if (type == &PyType_Type && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && (kwds == NULL || - (PyDict_Check(kwds) && PyDict_Size(kwds) == 0))) + (PyDict_Check(kwds) && PyDict_GET_SIZE(kwds) == 0))) return obj; /* If the returned object is not an instance of type, @@ -1585,7 +1585,7 @@ set_mro_error(PyObject *to_merge, int *remain) } } } - n = PyDict_Size(set); + n = PyDict_GET_SIZE(set); off = PyOS_snprintf(buf, sizeof(buf), "Cannot create a \ consistent method resolution\norder (MRO) for bases"); @@ -2187,7 +2187,7 @@ type_init(PyObject *cls, PyObject *args, PyObject *kwds) assert(kwds == NULL || PyDict_Check(kwds)); if (kwds != NULL && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1 && - PyDict_Check(kwds) && PyDict_Size(kwds) != 0) { + PyDict_Check(kwds) && PyDict_GET_SIZE(kwds) != 0) { PyErr_SetString(PyExc_TypeError, "type.__init__() takes no keyword arguments"); return -1; @@ -2272,7 +2272,7 @@ type_new(PyTypeObject *metatype, PyObject *args, PyObject *kwds) Note: We don't call PyType_CheckExact as that also allows subclasses */ if (metatype == &PyType_Type) { const Py_ssize_t nargs = PyTuple_GET_SIZE(args); - const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_Size(kwds); + const Py_ssize_t nkwds = kwds == NULL ? 0 : PyDict_GET_SIZE(kwds); if (nargs == 1 && nkwds == 0) { PyObject *x = PyTuple_GET_ITEM(args, 0); @@ -3416,7 +3416,7 @@ static int excess_args(PyObject *args, PyObject *kwds) { return PyTuple_GET_SIZE(args) || - (kwds && PyDict_Check(kwds) && PyDict_Size(kwds)); + (kwds && PyDict_Check(kwds) && PyDict_GET_SIZE(kwds)); } static int @@ -3894,7 +3894,7 @@ _PyObject_GetState(PyObject *obj, int required) We also return None if the dict is empty to make the behavior consistent regardless whether the dict was initialized or not. This make unit testing easier. */ - if (dict != NULL && *dict != NULL && PyDict_Size(*dict) > 0) { + if (dict != NULL && *dict != NULL && PyDict_GET_SIZE(*dict)) { state = *dict; } else { @@ -3983,7 +3983,7 @@ _PyObject_GetState(PyObject *obj, int required) /* If we found some slot attributes, pack them in a tuple along the original attribute dictionary. */ - if (PyDict_Size(slots) > 0) { + if (PyDict_GET_SIZE(slots) > 0) { PyObject *state2; state2 = PyTuple_Pack(2, state, slots); @@ -4175,7 +4175,7 @@ reduce_newobj(PyObject *obj) return NULL; } hasargs = (args != NULL); - if (kwargs == NULL || PyDict_Size(kwargs) == 0) { + if (kwargs == NULL || PyDict_GET_SIZE(kwargs) == 0) { _Py_IDENTIFIER(__newobj__); PyObject *cls; Py_ssize_t i, n; -- cgit v1.2.1 From b738df1cd4bcfdf6e01ea459ca559cd64f0bf6f3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 16 Dec 2016 19:19:02 +0200 Subject: Issue #18896: Python function can now have more than 255 parameters. collections.namedtuple() now supports tuples with more than 255 elements. --- Objects/codeobject.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'Objects') diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 788818d303..0857554adc 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -110,7 +110,7 @@ PyCode_New(int argcount, int kwonlyargcount, PyObject *lnotab) { PyCodeObject *co; - unsigned char *cell2arg = NULL; + Py_ssize_t *cell2arg = NULL; Py_ssize_t i, n_cellvars; /* Check argument types */ @@ -142,19 +142,25 @@ PyCode_New(int argcount, int kwonlyargcount, if (n_cellvars) { Py_ssize_t total_args = argcount + kwonlyargcount + ((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0); - Py_ssize_t alloc_size = sizeof(unsigned char) * n_cellvars; bool used_cell2arg = false; - cell2arg = PyMem_MALLOC(alloc_size); - if (cell2arg == NULL) + cell2arg = PyMem_NEW(Py_ssize_t, n_cellvars); + if (cell2arg == NULL) { + PyErr_NoMemory(); return NULL; - memset(cell2arg, CO_CELL_NOT_AN_ARG, alloc_size); + } /* Find cells which are also arguments. */ for (i = 0; i < n_cellvars; i++) { Py_ssize_t j; PyObject *cell = PyTuple_GET_ITEM(cellvars, i); + cell2arg[i] = CO_CELL_NOT_AN_ARG; for (j = 0; j < total_args; j++) { PyObject *arg = PyTuple_GET_ITEM(varnames, j); - if (!PyUnicode_Compare(cell, arg)) { + int cmp = PyUnicode_Compare(cell, arg); + if (cmp == -1 && PyErr_Occurred()) { + PyMem_FREE(cell2arg); + return NULL; + } + if (cmp == 0) { cell2arg[i] = j; used_cell2arg = true; break; @@ -449,7 +455,7 @@ code_sizeof(PyCodeObject *co, void *unused) res = _PyObject_SIZE(Py_TYPE(co)); if (co->co_cell2arg != NULL && co->co_cellvars != NULL) - res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(unsigned char); + res += PyTuple_GET_SIZE(co->co_cellvars) * sizeof(Py_ssize_t); return PyLong_FromSsize_t(res); } -- cgit v1.2.1 From d33309cd9787b4ab16f5bbc6abb6ad3f7c6f42f7 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 19 Dec 2016 18:51:37 +0200 Subject: Issue #28927: bytes.fromhex() and bytearray.fromhex() now ignore all ASCII whitespace, not only spaces. Patch by Robert Xiao. --- Objects/bytesobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'Objects') diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 0df90335ed..5bdfd62f96 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -2378,10 +2378,10 @@ _PyBytes_FromHex(PyObject *string, int use_bytearray) end = str + hexlen; while (str < end) { /* skip over spaces in the input */ - if (*str == ' ') { + if (Py_ISSPACE(*str)) { do { str++; - } while (*str == ' '); + } while (Py_ISSPACE(*str)); if (str >= end) break; } -- cgit v1.2.1 From bed50e1fd3e82021bd51be24920880518268372e Mon Sep 17 00:00:00 2001 From: Xiang Zhang Date: Tue, 20 Dec 2016 22:52:33 +0800 Subject: Issue #28822: Adjust indices handling of PyUnicode_FindChar(). --- Objects/unicodeobject.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'Objects') diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 3fdce82ae6..bbda4d884c 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -9461,16 +9461,12 @@ PyUnicode_FindChar(PyObject *str, Py_UCS4 ch, int direction) { int kind; - Py_ssize_t result; + Py_ssize_t len, result; if (PyUnicode_READY(str) == -1) return -2; - if (start < 0 || end < 0) { - PyErr_SetString(PyExc_IndexError, "string index out of range"); - return -2; - } - if (end > PyUnicode_GET_LENGTH(str)) - end = PyUnicode_GET_LENGTH(str); - if (start >= end) + len = PyUnicode_GET_LENGTH(str); + ADJUST_INDICES(start, end, len); + if (end - start < 1) return -1; kind = PyUnicode_KIND(str); result = findchar(PyUnicode_1BYTE_DATA(str) + kind*start, -- cgit v1.2.1 From febbf471bd550945621b470089b6c3dc872ae894 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Sat, 24 Dec 2016 20:19:08 +0900 Subject: Issue #29049: Call _PyObject_GC_TRACK() lazily when calling Python function. Calling function is up to 5% faster. --- Objects/frameobject.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'Objects') diff --git a/Objects/frameobject.c b/Objects/frameobject.c index eed538498c..84483195ab 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -415,7 +415,9 @@ frame_dealloc(PyFrameObject *f) PyObject **p, **valuestack; PyCodeObject *co; - PyObject_GC_UnTrack(f); + if (_PyObject_GC_IS_TRACKED(f)) + _PyObject_GC_UNTRACK(f); + Py_TRASHCAN_SAFE_BEGIN(f) /* Kill all local variables */ valuestack = f->f_valuestack; @@ -606,8 +608,8 @@ int _PyFrame_Init() } PyFrameObject* _Py_HOT_FUNCTION -PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, - PyObject *locals) +_PyFrame_New_NoTrack(PyThreadState *tstate, PyCodeObject *code, + PyObject *globals, PyObject *locals) { PyFrameObject *back = tstate->frame; PyFrameObject *f; @@ -727,10 +729,20 @@ PyFrame_New(PyThreadState *tstate, PyCodeObject *code, PyObject *globals, f->f_executing = 0; f->f_gen = NULL; - _PyObject_GC_TRACK(f); return f; } +PyFrameObject* +PyFrame_New(PyThreadState *tstate, PyCodeObject *code, + PyObject *globals, PyObject *locals) +{ + PyFrameObject *f = _PyFrame_New_NoTrack(tstate, code, globals, locals); + if (f) + _PyObject_GC_TRACK(f); + return f; +} + + /* Block management */ void -- cgit v1.2.1 From 4b375633441132133e8d633fef50c4a4af64e091 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 3 Jan 2017 01:58:17 +0100 Subject: Issue #28839: Optimize function_call() function_call() now simply calls _PyFunction_FastCallDict(). _PyFunction_FastCallDict() is more efficient: it contains fast paths for the common case (optimized code object and no keyword argument). --- Objects/funcobject.c | 53 ++++++---------------------------------------------- 1 file changed, 6 insertions(+), 47 deletions(-) (limited to 'Objects') diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 63aa9de583..a3af4b372a 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -563,55 +563,14 @@ func_traverse(PyFunctionObject *f, visitproc visit, void *arg) } static PyObject * -function_call(PyObject *func, PyObject *arg, PyObject *kw) +function_call(PyObject *func, PyObject *args, PyObject *kwargs) { - PyObject *result; - PyObject *argdefs; - PyObject *kwtuple = NULL; - PyObject **d, **k; - Py_ssize_t nk, nd; - - argdefs = PyFunction_GET_DEFAULTS(func); - if (argdefs != NULL && PyTuple_Check(argdefs)) { - d = &PyTuple_GET_ITEM((PyTupleObject *)argdefs, 0); - nd = PyTuple_GET_SIZE(argdefs); - } - else { - d = NULL; - nd = 0; - } - - if (kw != NULL && PyDict_Check(kw)) { - Py_ssize_t pos, i; - nk = PyDict_GET_SIZE(kw); - kwtuple = PyTuple_New(2*nk); - if (kwtuple == NULL) - return NULL; - k = &PyTuple_GET_ITEM(kwtuple, 0); - pos = i = 0; - while (PyDict_Next(kw, &pos, &k[i], &k[i+1])) { - Py_INCREF(k[i]); - Py_INCREF(k[i+1]); - i += 2; - } - nk = i/2; - } - else { - k = NULL; - nk = 0; - } - - result = PyEval_EvalCodeEx( - PyFunction_GET_CODE(func), - PyFunction_GET_GLOBALS(func), (PyObject *)NULL, - &PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg), - k, nk, d, nd, - PyFunction_GET_KW_DEFAULTS(func), - PyFunction_GET_CLOSURE(func)); - - Py_XDECREF(kwtuple); + PyObject **stack; + Py_ssize_t nargs; - return result; + stack = &PyTuple_GET_ITEM(args, 0); + nargs = PyTuple_GET_SIZE(args); + return _PyFunction_FastCallDict(func, stack, nargs, kwargs); } /* Bind a function to an object */ -- cgit v1.2.1 From a8ccebab461e0c74a522f55fc25bef949d34ef29 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 11 Jan 2017 00:07:40 +0100 Subject: call_method() now uses _PyObject_FastCall() Issue #29233: Replace the inefficient _PyObject_VaCallFunctionObjArgs() with _PyObject_FastCall() in call_method() and call_maybe(). Only a few functions call call_method() and call it with a fixed number of arguments. Avoid the complex and expensive _PyObject_VaCallFunctionObjArgs() function, replace it with an array allocated on the stack with the exact number of argumlents. It reduces the stack consumption, bytes per call, before => after: test_python_call: 1168 => 1152 (-16 B) test_python_getitem: 1344 => 1008 (-336 B) test_python_iterator: 1568 => 1232 (-336 B) Remove the _PyObject_VaCallFunctionObjArgs() function which became useless. Rename it to object_vacall() and make it private. --- Objects/abstract.c | 10 +++--- Objects/typeobject.c | 100 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 66 insertions(+), 44 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 8d1eddc093..93bf87fa88 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2700,8 +2700,8 @@ _PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name, return retval; } -PyObject * -_PyObject_VaCallFunctionObjArgs(PyObject *callable, va_list vargs) +static PyObject * +object_vacall(PyObject *callable, va_list vargs) { PyObject *small_stack[_PY_FASTCALL_SMALL_STACK]; PyObject **stack; @@ -2767,7 +2767,7 @@ PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...) } va_start(vargs, name); - result = _PyObject_VaCallFunctionObjArgs(callable, vargs); + result = object_vacall(callable, vargs); va_end(vargs); Py_DECREF(callable); @@ -2791,7 +2791,7 @@ _PyObject_CallMethodIdObjArgs(PyObject *obj, } va_start(vargs, name); - result = _PyObject_VaCallFunctionObjArgs(callable, vargs); + result = object_vacall(callable, vargs); va_end(vargs); Py_DECREF(callable); @@ -2805,7 +2805,7 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...) PyObject *result; va_start(vargs, callable); - result = _PyObject_VaCallFunctionObjArgs(callable, vargs); + result = object_vacall(callable, vargs); va_end(vargs); return result; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 37f0082587..05fc7b88d3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1425,9 +1425,9 @@ _PyObject_LookupSpecial(PyObject *self, _Py_Identifier *attrid) as lookup_method to cache the interned name string object. */ static PyObject * -call_method(PyObject *obj, _Py_Identifier *name, ...) +call_method(PyObject *obj, _Py_Identifier *name, + PyObject **args, Py_ssize_t nargs) { - va_list va; PyObject *func, *retval; func = lookup_maybe(obj, name); @@ -1437,10 +1437,7 @@ call_method(PyObject *obj, _Py_Identifier *name, ...) return NULL; } - va_start(va, name); - retval = _PyObject_VaCallFunctionObjArgs(func, va); - va_end(va); - + retval = _PyObject_FastCall(func, args, nargs); Py_DECREF(func); return retval; @@ -1449,9 +1446,9 @@ call_method(PyObject *obj, _Py_Identifier *name, ...) /* Clone of call_method() that returns NotImplemented when the lookup fails. */ static PyObject * -call_maybe(PyObject *obj, _Py_Identifier *name, ...) +call_maybe(PyObject *obj, _Py_Identifier *name, + PyObject **args, Py_ssize_t nargs) { - va_list va; PyObject *func, *retval; func = lookup_maybe(obj, name); @@ -1461,10 +1458,7 @@ call_maybe(PyObject *obj, _Py_Identifier *name, ...) return NULL; } - va_start(va, name); - retval = _PyObject_VaCallFunctionObjArgs(func, va); - va_end(va); - + retval = _PyObject_FastCall(func, args, nargs); Py_DECREF(func); return retval; @@ -5701,15 +5695,16 @@ static PyObject * \ FUNCNAME(PyObject *self) \ { \ _Py_static_string(id, OPSTR); \ - return call_method(self, &id, NULL); \ + return call_method(self, &id, NULL, 0); \ } #define SLOT1(FUNCNAME, OPSTR, ARG1TYPE) \ static PyObject * \ FUNCNAME(PyObject *self, ARG1TYPE arg1) \ { \ + PyObject* stack[1] = {arg1}; \ _Py_static_string(id, OPSTR); \ - return call_method(self, &id, arg1, NULL); \ + return call_method(self, &id, stack, 1); \ } /* Boolean helper for SLOT1BINFULL(). @@ -5751,6 +5746,7 @@ method_is_overloaded(PyObject *left, PyObject *right, struct _Py_Identifier *nam static PyObject * \ FUNCNAME(PyObject *self, PyObject *other) \ { \ + PyObject* stack[1]; \ _Py_static_string(op_id, OPSTR); \ _Py_static_string(rop_id, ROPSTR); \ int do_other = Py_TYPE(self) != Py_TYPE(other) && \ @@ -5762,20 +5758,23 @@ FUNCNAME(PyObject *self, PyObject *other) \ if (do_other && \ PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self)) && \ method_is_overloaded(self, other, &rop_id)) { \ - r = call_maybe(other, &rop_id, self, NULL); \ + stack[0] = self; \ + r = call_maybe(other, &rop_id, stack, 1); \ if (r != Py_NotImplemented) \ return r; \ Py_DECREF(r); \ do_other = 0; \ } \ - r = call_maybe(self, &op_id, other, NULL); \ + stack[0] = other; \ + r = call_maybe(self, &op_id, stack, 1); \ if (r != Py_NotImplemented || \ Py_TYPE(other) == Py_TYPE(self)) \ return r; \ Py_DECREF(r); \ } \ if (do_other) { \ - return call_maybe(other, &rop_id, self, NULL); \ + stack[0] = self; \ + return call_maybe(other, &rop_id, stack, 1); \ } \ Py_RETURN_NOTIMPLEMENTED; \ } @@ -5786,7 +5785,7 @@ FUNCNAME(PyObject *self, PyObject *other) \ static Py_ssize_t slot_sq_length(PyObject *self) { - PyObject *res = call_method(self, &PyId___len__, NULL); + PyObject *res = call_method(self, &PyId___len__, NULL, 0); Py_ssize_t len; if (res == NULL) @@ -5846,6 +5845,7 @@ error: static int slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value) { + PyObject *stack[2]; PyObject *res; PyObject *index_obj; @@ -5854,10 +5854,14 @@ slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value) return -1; } - if (value == NULL) - res = call_method(self, &PyId___delitem__, index_obj, NULL); - else - res = call_method(self, &PyId___setitem__, index_obj, value, NULL); + stack[0] = index_obj; + if (value == NULL) { + res = call_method(self, &PyId___delitem__, stack, 1); + } + else { + stack[1] = value; + res = call_method(self, &PyId___setitem__, stack, 2); + } Py_DECREF(index_obj); if (res == NULL) { @@ -5905,12 +5909,17 @@ SLOT1(slot_mp_subscript, "__getitem__", PyObject *) static int slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value) { + PyObject *stack[2]; PyObject *res; - if (value == NULL) - res = call_method(self, &PyId___delitem__, key, NULL); - else - res = call_method(self, &PyId___setitem__, key, value, NULL); + stack[0] = key; + if (value == NULL) { + res = call_method(self, &PyId___delitem__, stack, 1); + } + else { + stack[1] = value; + res = call_method(self, &PyId___setitem__, stack, 2); + } if (res == NULL) return -1; @@ -5942,7 +5951,8 @@ slot_nb_power(PyObject *self, PyObject *other, PyObject *modulus) slot_nb_power, so check before calling self.__pow__. */ if (Py_TYPE(self)->tp_as_number != NULL && Py_TYPE(self)->tp_as_number->nb_power == slot_nb_power) { - return call_method(self, &PyId___pow__, other, modulus, NULL); + PyObject* stack[2] = {other, modulus}; + return call_method(self, &PyId___pow__, stack, 2); } Py_RETURN_NOTIMPLEMENTED; } @@ -6009,7 +6019,7 @@ static PyObject * slot_nb_index(PyObject *self) { _Py_IDENTIFIER(__index__); - return call_method(self, &PyId___index__, NULL); + return call_method(self, &PyId___index__, NULL, 0); } @@ -6031,8 +6041,9 @@ SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *) static PyObject * slot_nb_inplace_power(PyObject *self, PyObject * arg1, PyObject *arg2) { + PyObject *stack[1] = {arg1}; _Py_IDENTIFIER(__ipow__); - return call_method(self, &PyId___ipow__, arg1, NULL); + return call_method(self, &PyId___ipow__, stack, 1); } SLOT1(slot_nb_inplace_lshift, "__ilshift__", PyObject *) SLOT1(slot_nb_inplace_rshift, "__irshift__", PyObject *) @@ -6153,7 +6164,8 @@ slot_tp_call(PyObject *self, PyObject *args, PyObject *kwds) static PyObject * slot_tp_getattro(PyObject *self, PyObject *name) { - return call_method(self, &PyId___getattribute__, name, NULL); + PyObject *stack[1] = {name}; + return call_method(self, &PyId___getattribute__, stack, 1); } static PyObject * @@ -6220,14 +6232,19 @@ slot_tp_getattr_hook(PyObject *self, PyObject *name) static int slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value) { + PyObject *stack[2]; PyObject *res; _Py_IDENTIFIER(__delattr__); _Py_IDENTIFIER(__setattr__); - if (value == NULL) - res = call_method(self, &PyId___delattr__, name, NULL); - else - res = call_method(self, &PyId___setattr__, name, value, NULL); + stack[0] = name; + if (value == NULL) { + res = call_method(self, &PyId___delattr__, stack, 1); + } + else { + stack[1] = value; + res = call_method(self, &PyId___setattr__, stack, 2); + } if (res == NULL) return -1; Py_DECREF(res); @@ -6295,7 +6312,7 @@ static PyObject * slot_tp_iternext(PyObject *self) { _Py_IDENTIFIER(__next__); - return call_method(self, &PyId___next__, NULL); + return call_method(self, &PyId___next__, NULL, 0); } static PyObject * @@ -6323,14 +6340,19 @@ slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type) static int slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value) { + PyObject* stack[2]; PyObject *res; _Py_IDENTIFIER(__delete__); _Py_IDENTIFIER(__set__); - if (value == NULL) - res = call_method(self, &PyId___delete__, target, NULL); - else - res = call_method(self, &PyId___set__, target, value, NULL); + stack[0] = target; + if (value == NULL) { + res = call_method(self, &PyId___delete__, stack, 1); + } + else { + stack[1] = value; + res = call_method(self, &PyId___set__, stack, 2); + } if (res == NULL) return -1; Py_DECREF(res); -- cgit v1.2.1 From 3106ff9ad570b650a3afee6ebc4adc7430c5eca2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 11 Jan 2017 01:07:03 +0100 Subject: Disable _PyStack_AsTuple() inlining Issue #29234: Inlining _PyStack_AsTuple() into callers increases their stack consumption, Disable inlining to optimize the stack consumption. Add _Py_NO_INLINE: use __attribute__((noinline)) of GCC and Clang. It reduces the stack consumption, bytes per call, before => after: test_python_call: 1040 => 976 (-64 B) test_python_getitem: 976 => 912 (-64 B) test_python_iterator: 1120 => 1056 (-64 B) => total: 3136 => 2944 (- 192 B) --- Objects/abstract.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 93bf87fa88..5726160c08 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2256,7 +2256,9 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) return _Py_CheckFunctionResult(callable, result, NULL); } -PyObject* +/* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their + stack consumption, Disable inlining to optimize the stack consumption. */ +PyObject* _Py_NO_INLINE _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) { PyObject *args; -- cgit v1.2.1 From 16cb329a27acf161b2db78a8b60e89e600c42f1b Mon Sep 17 00:00:00 2001 From: Martin Panter Date: Sat, 14 Jan 2017 06:30:37 +0000 Subject: Issue #1621: Overflow should not be possible in listextend() --- Objects/listobject.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Objects') diff --git a/Objects/listobject.c b/Objects/listobject.c index dcd7b5efe5..05dddfc6d7 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -804,6 +804,9 @@ listextend(PyListObject *self, PyObject *b) Py_RETURN_NONE; } m = Py_SIZE(self); + /* It should not be possible to allocate a list large enough to cause + an overflow on any relevant platform */ + assert(m < PY_SSIZE_T_MAX - n); if (list_resize(self, m + n) < 0) { Py_DECREF(b); return NULL; -- cgit v1.2.1 From 70249059aaa99129a75a69f75dddfb5731a71585 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Mon, 16 Jan 2017 20:41:20 +0900 Subject: Issue #20180: convert unicode methods to AC. --- Objects/clinic/unicodeobject.c.h | 895 +++++++++++++++++++++++++++++++++++++- Objects/unicodeobject.c | 919 ++++++++++++++++++++++----------------- 2 files changed, 1405 insertions(+), 409 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index 891e90c312..5873ce1972 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -2,6 +2,790 @@ preserve [clinic start generated code]*/ +PyDoc_STRVAR(unicode_title__doc__, +"title($self, /)\n" +"--\n" +"\n" +"Return a version of the string where each word is capitalized.\n" +"\n" +"More specifically, words start with upper cased characters and all remaining\n" +"cased characters have lower case."); + +#define UNICODE_TITLE_METHODDEF \ + {"title", (PyCFunction)unicode_title, METH_NOARGS, unicode_title__doc__}, + +static PyObject * +unicode_title_impl(PyObject *self); + +static PyObject * +unicode_title(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_title_impl(self); +} + +PyDoc_STRVAR(unicode_capitalize__doc__, +"capitalize($self, /)\n" +"--\n" +"\n" +"Return a capitalized version of the string.\n" +"\n" +"More specifically, make the first character have upper case and the rest lower\n" +"case."); + +#define UNICODE_CAPITALIZE_METHODDEF \ + {"capitalize", (PyCFunction)unicode_capitalize, METH_NOARGS, unicode_capitalize__doc__}, + +static PyObject * +unicode_capitalize_impl(PyObject *self); + +static PyObject * +unicode_capitalize(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_capitalize_impl(self); +} + +PyDoc_STRVAR(unicode_casefold__doc__, +"casefold($self, /)\n" +"--\n" +"\n" +"Return a version of S suitable for caseless comparisons."); + +#define UNICODE_CASEFOLD_METHODDEF \ + {"casefold", (PyCFunction)unicode_casefold, METH_NOARGS, unicode_casefold__doc__}, + +static PyObject * +unicode_casefold_impl(PyObject *self); + +static PyObject * +unicode_casefold(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_casefold_impl(self); +} + +PyDoc_STRVAR(unicode_center__doc__, +"center($self, width, fillchar=\' \', /)\n" +"--\n" +"\n" +"Return a centered string of length width.\n" +"\n" +"Padding is done using the specified fill character (default is a space)."); + +#define UNICODE_CENTER_METHODDEF \ + {"center", (PyCFunction)unicode_center, METH_VARARGS, unicode_center__doc__}, + +static PyObject * +unicode_center_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar); + +static PyObject * +unicode_center(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t width; + Py_UCS4 fillchar = ' '; + + if (!PyArg_ParseTuple(args, "n|O&:center", + &width, convert_uc, &fillchar)) { + goto exit; + } + return_value = unicode_center_impl(self, width, fillchar); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_encode__doc__, +"encode($self, /, encoding=\'utf-8\', errors=\'strict\')\n" +"--\n" +"\n" +"Encode a string using the codec registered for encoding.\n" +"\n" +" encoding\n" +" The encoding in which to encode the string.\n" +" errors\n" +" The error handling scheme to use for the handling of encoding errors.\n" +" The default is \'strict\' meaning that encoding errors raise a\n" +" UnicodeEncodeError. Other possible values are \'ignore\', \'replace\' and\n" +" \'xmlcharrefreplace\' as well as any other name registered with\n" +" codecs.register_error that can handle UnicodeEncodeErrors."); + +#define UNICODE_ENCODE_METHODDEF \ + {"encode", (PyCFunction)unicode_encode, METH_FASTCALL, unicode_encode__doc__}, + +static PyObject * +unicode_encode_impl(PyObject *self, const char *encoding, const char *errors); + +static PyObject * +unicode_encode(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"encoding", "errors", NULL}; + static _PyArg_Parser _parser = {"|ss:encode", _keywords, 0}; + const char *encoding = NULL; + const char *errors = NULL; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &encoding, &errors)) { + goto exit; + } + return_value = unicode_encode_impl(self, encoding, errors); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_expandtabs__doc__, +"expandtabs($self, /, tabsize=8)\n" +"--\n" +"\n" +"Return a copy where all tab characters are expanded using spaces.\n" +"\n" +"If tabsize is not given, a tab size of 8 characters is assumed."); + +#define UNICODE_EXPANDTABS_METHODDEF \ + {"expandtabs", (PyCFunction)unicode_expandtabs, METH_FASTCALL, unicode_expandtabs__doc__}, + +static PyObject * +unicode_expandtabs_impl(PyObject *self, int tabsize); + +static PyObject * +unicode_expandtabs(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"tabsize", NULL}; + static _PyArg_Parser _parser = {"|i:expandtabs", _keywords, 0}; + int tabsize = 8; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &tabsize)) { + goto exit; + } + return_value = unicode_expandtabs_impl(self, tabsize); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_islower__doc__, +"islower($self, /)\n" +"--\n" +"\n" +"Return whether the string is a lowercase string; False otherwise.\n" +"\n" +"A string is lowercase if all cased characters in the string are lowercase and\n" +"there is at least one cased character in the string."); + +#define UNICODE_ISLOWER_METHODDEF \ + {"islower", (PyCFunction)unicode_islower, METH_NOARGS, unicode_islower__doc__}, + +static PyObject * +unicode_islower_impl(PyObject *self); + +static PyObject * +unicode_islower(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_islower_impl(self); +} + +PyDoc_STRVAR(unicode_isupper__doc__, +"isupper($self, /)\n" +"--\n" +"\n" +"Return True if the string is an uppercase string; False otherwise.\n" +"\n" +"A string is uppercase if all cased characters in the string are uppercase and\n" +"there is at least one cased character in the string."); + +#define UNICODE_ISUPPER_METHODDEF \ + {"isupper", (PyCFunction)unicode_isupper, METH_NOARGS, unicode_isupper__doc__}, + +static PyObject * +unicode_isupper_impl(PyObject *self); + +static PyObject * +unicode_isupper(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_isupper_impl(self); +} + +PyDoc_STRVAR(unicode_istitle__doc__, +"istitle($self, /)\n" +"--\n" +"\n" +"Return True if the string is a title-cased string; False otherwise.\n" +"\n" +"In a title-cased string, upper- and title-case characters may only\n" +"follow uncased characters and lowercase characters only cased ones."); + +#define UNICODE_ISTITLE_METHODDEF \ + {"istitle", (PyCFunction)unicode_istitle, METH_NOARGS, unicode_istitle__doc__}, + +static PyObject * +unicode_istitle_impl(PyObject *self); + +static PyObject * +unicode_istitle(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_istitle_impl(self); +} + +PyDoc_STRVAR(unicode_isspace__doc__, +"isspace($self, /)\n" +"--\n" +"\n" +"Return True if the string is a whitespace string; False otherwise.\n" +"\n" +"A string is whitespace if all characters in the string are whitespace and there\n" +"is at least one character in the string."); + +#define UNICODE_ISSPACE_METHODDEF \ + {"isspace", (PyCFunction)unicode_isspace, METH_NOARGS, unicode_isspace__doc__}, + +static PyObject * +unicode_isspace_impl(PyObject *self); + +static PyObject * +unicode_isspace(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_isspace_impl(self); +} + +PyDoc_STRVAR(unicode_isalpha__doc__, +"isalpha($self, /)\n" +"--\n" +"\n" +"Return True if the string is an alphabetic string; False otherwise.\n" +"\n" +"A string is alphabetic if all characters in the string are alphabetic and there\n" +"is at least one character in the string."); + +#define UNICODE_ISALPHA_METHODDEF \ + {"isalpha", (PyCFunction)unicode_isalpha, METH_NOARGS, unicode_isalpha__doc__}, + +static PyObject * +unicode_isalpha_impl(PyObject *self); + +static PyObject * +unicode_isalpha(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_isalpha_impl(self); +} + +PyDoc_STRVAR(unicode_isalnum__doc__, +"isalnum($self, /)\n" +"--\n" +"\n" +"Return True if the string is an alpha-numeric string; False otherwise.\n" +"\n" +"A string is alpha-numeric if all characters in the string are alpha-numeric and\n" +"there is at least one character in the string."); + +#define UNICODE_ISALNUM_METHODDEF \ + {"isalnum", (PyCFunction)unicode_isalnum, METH_NOARGS, unicode_isalnum__doc__}, + +static PyObject * +unicode_isalnum_impl(PyObject *self); + +static PyObject * +unicode_isalnum(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_isalnum_impl(self); +} + +PyDoc_STRVAR(unicode_isdecimal__doc__, +"isdecimal($self, /)\n" +"--\n" +"\n" +"Return True if the string is a decimal string; False otherwise.\n" +"\n" +"A string is a digit string if all characters in the string are decimal and\n" +"there is at least one character in the string."); + +#define UNICODE_ISDECIMAL_METHODDEF \ + {"isdecimal", (PyCFunction)unicode_isdecimal, METH_NOARGS, unicode_isdecimal__doc__}, + +static PyObject * +unicode_isdecimal_impl(PyObject *self); + +static PyObject * +unicode_isdecimal(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_isdecimal_impl(self); +} + +PyDoc_STRVAR(unicode_isdigit__doc__, +"isdigit($self, /)\n" +"--\n" +"\n" +"Return True if the string is a digit string; False otherwise.\n" +"\n" +"A string is a digit string if all characters in the string are digits and there\n" +"is at least one character in the string."); + +#define UNICODE_ISDIGIT_METHODDEF \ + {"isdigit", (PyCFunction)unicode_isdigit, METH_NOARGS, unicode_isdigit__doc__}, + +static PyObject * +unicode_isdigit_impl(PyObject *self); + +static PyObject * +unicode_isdigit(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_isdigit_impl(self); +} + +PyDoc_STRVAR(unicode_isnumeric__doc__, +"isnumeric($self, /)\n" +"--\n" +"\n" +"Return True if the string is an numeric string; False otherwise.\n" +"\n" +"A string is numeric if all characters in the string are numeric and there is at\n" +"least one character in the string."); + +#define UNICODE_ISNUMERIC_METHODDEF \ + {"isnumeric", (PyCFunction)unicode_isnumeric, METH_NOARGS, unicode_isnumeric__doc__}, + +static PyObject * +unicode_isnumeric_impl(PyObject *self); + +static PyObject * +unicode_isnumeric(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_isnumeric_impl(self); +} + +PyDoc_STRVAR(unicode_isidentifier__doc__, +"isidentifier($self, /)\n" +"--\n" +"\n" +"Return True if the string is a valid Python identifier; False otherwise.\n" +"\n" +"Use keyword.iskeyword() to test for reserved identifiers such as \"def\" and\n" +"\"class\"."); + +#define UNICODE_ISIDENTIFIER_METHODDEF \ + {"isidentifier", (PyCFunction)unicode_isidentifier, METH_NOARGS, unicode_isidentifier__doc__}, + +static PyObject * +unicode_isidentifier_impl(PyObject *self); + +static PyObject * +unicode_isidentifier(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_isidentifier_impl(self); +} + +PyDoc_STRVAR(unicode_isprintable__doc__, +"isprintable($self, /)\n" +"--\n" +"\n" +"Return True if the string is printable; False otherwise.\n" +"\n" +"A string is printable if all of its characters are considered printable in\n" +"repr() or if it is empty."); + +#define UNICODE_ISPRINTABLE_METHODDEF \ + {"isprintable", (PyCFunction)unicode_isprintable, METH_NOARGS, unicode_isprintable__doc__}, + +static PyObject * +unicode_isprintable_impl(PyObject *self); + +static PyObject * +unicode_isprintable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_isprintable_impl(self); +} + +PyDoc_STRVAR(unicode_join__doc__, +"join($self, iterable, /)\n" +"--\n" +"\n" +"Concatenate any number of strings.\n" +"\n" +"The string whose method is called is inserted in between each pair of given\n" +"strings.\n" +"\n" +"The result is returned as a new string.\n" +"\n" +"Example: \'.\'.join([\'ab\', \'pq\', \'rs\']) -> \'ab.pq.rs\'"); + +#define UNICODE_JOIN_METHODDEF \ + {"join", (PyCFunction)unicode_join, METH_O, unicode_join__doc__}, + +PyDoc_STRVAR(unicode_ljust__doc__, +"ljust($self, width, fillchar=\' \', /)\n" +"--\n" +"\n" +"Return a left-justified string of length width.\n" +"\n" +"Padding is done using the specified fill character (default is a space)."); + +#define UNICODE_LJUST_METHODDEF \ + {"ljust", (PyCFunction)unicode_ljust, METH_VARARGS, unicode_ljust__doc__}, + +static PyObject * +unicode_ljust_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar); + +static PyObject * +unicode_ljust(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t width; + Py_UCS4 fillchar = ' '; + + if (!PyArg_ParseTuple(args, "n|O&:ljust", + &width, convert_uc, &fillchar)) { + goto exit; + } + return_value = unicode_ljust_impl(self, width, fillchar); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_lower__doc__, +"lower($self, /)\n" +"--\n" +"\n" +"Return a copy of the string converted to lowercase."); + +#define UNICODE_LOWER_METHODDEF \ + {"lower", (PyCFunction)unicode_lower, METH_NOARGS, unicode_lower__doc__}, + +static PyObject * +unicode_lower_impl(PyObject *self); + +static PyObject * +unicode_lower(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_lower_impl(self); +} + +PyDoc_STRVAR(unicode_strip__doc__, +"strip($self, chars=None, /)\n" +"--\n" +"\n" +"Return a copy of the string with leading and trailing whitespace removed.\n" +"\n" +"If chars is given and not None, remove characters in chars instead."); + +#define UNICODE_STRIP_METHODDEF \ + {"strip", (PyCFunction)unicode_strip, METH_VARARGS, unicode_strip__doc__}, + +static PyObject * +unicode_strip_impl(PyObject *self, PyObject *chars); + +static PyObject * +unicode_strip(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *chars = Py_None; + + if (!PyArg_UnpackTuple(args, "strip", + 0, 1, + &chars)) { + goto exit; + } + return_value = unicode_strip_impl(self, chars); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_lstrip__doc__, +"lstrip($self, chars=None, /)\n" +"--\n" +"\n" +"Return a copy of the string with leading whitespace removed.\n" +"\n" +"If chars is given and not None, remove characters in chars instead."); + +#define UNICODE_LSTRIP_METHODDEF \ + {"lstrip", (PyCFunction)unicode_lstrip, METH_VARARGS, unicode_lstrip__doc__}, + +static PyObject * +unicode_lstrip_impl(PyObject *self, PyObject *chars); + +static PyObject * +unicode_lstrip(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *chars = NULL; + + if (!PyArg_UnpackTuple(args, "lstrip", + 0, 1, + &chars)) { + goto exit; + } + return_value = unicode_lstrip_impl(self, chars); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_rstrip__doc__, +"rstrip($self, chars=None, /)\n" +"--\n" +"\n" +"Return a copy of the string with trailing whitespace removed.\n" +"\n" +"If chars is given and not None, remove characters in chars instead."); + +#define UNICODE_RSTRIP_METHODDEF \ + {"rstrip", (PyCFunction)unicode_rstrip, METH_VARARGS, unicode_rstrip__doc__}, + +static PyObject * +unicode_rstrip_impl(PyObject *self, PyObject *chars); + +static PyObject * +unicode_rstrip(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *chars = NULL; + + if (!PyArg_UnpackTuple(args, "rstrip", + 0, 1, + &chars)) { + goto exit; + } + return_value = unicode_rstrip_impl(self, chars); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_replace__doc__, +"replace($self, old, new, count=-1, /)\n" +"--\n" +"\n" +"Return a copy with all occurrences of substring old replaced by new.\n" +"\n" +" count\n" +" Maximum number of occurrences to replace.\n" +" -1 (the default value) means replace all occurrences.\n" +"\n" +"If the optional argument count is given, only the first count occurrences are\n" +"replaced."); + +#define UNICODE_REPLACE_METHODDEF \ + {"replace", (PyCFunction)unicode_replace, METH_VARARGS, unicode_replace__doc__}, + +static PyObject * +unicode_replace_impl(PyObject *self, PyObject *old, PyObject *new, + Py_ssize_t count); + +static PyObject * +unicode_replace(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + PyObject *old; + PyObject *new; + Py_ssize_t count = -1; + + if (!PyArg_ParseTuple(args, "UU|n:replace", + &old, &new, &count)) { + goto exit; + } + return_value = unicode_replace_impl(self, old, new, count); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_rjust__doc__, +"rjust($self, width, fillchar=\' \', /)\n" +"--\n" +"\n" +"Return a right-justified string of length width.\n" +"\n" +"Padding is done using the specified fill character (default is a space)."); + +#define UNICODE_RJUST_METHODDEF \ + {"rjust", (PyCFunction)unicode_rjust, METH_VARARGS, unicode_rjust__doc__}, + +static PyObject * +unicode_rjust_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar); + +static PyObject * +unicode_rjust(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + Py_ssize_t width; + Py_UCS4 fillchar = ' '; + + if (!PyArg_ParseTuple(args, "n|O&:rjust", + &width, convert_uc, &fillchar)) { + goto exit; + } + return_value = unicode_rjust_impl(self, width, fillchar); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_split__doc__, +"split($self, /, sep=None, maxsplit=-1)\n" +"--\n" +"\n" +"Return a list of the words in the string, using sep as the delimiter string.\n" +"\n" +" sep\n" +" The delimiter according which to split the string.\n" +" None (the default value) means split according to any whitespace,\n" +" and discard empty strings from the result.\n" +" maxsplit\n" +" Maximum number of splits to do.\n" +" -1 (the default value) means no limit."); + +#define UNICODE_SPLIT_METHODDEF \ + {"split", (PyCFunction)unicode_split, METH_FASTCALL, unicode_split__doc__}, + +static PyObject * +unicode_split_impl(PyObject *self, PyObject *sep, Py_ssize_t maxsplit); + +static PyObject * +unicode_split(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"sep", "maxsplit", NULL}; + static _PyArg_Parser _parser = {"|On:split", _keywords, 0}; + PyObject *sep = Py_None; + Py_ssize_t maxsplit = -1; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &sep, &maxsplit)) { + goto exit; + } + return_value = unicode_split_impl(self, sep, maxsplit); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_partition__doc__, +"partition($self, sep, /)\n" +"--\n" +"\n" +"Partition the string into three parts using the given separator.\n" +"\n" +"This will search for the separator in the string. If the separator is found,\n" +"returns a 3-tuple containing the part before the separator, the separator\n" +"itself, and the part after it.\n" +"\n" +"If the separator is not found, returns a 3-tuple containing the original string\n" +"and two empty strings."); + +#define UNICODE_PARTITION_METHODDEF \ + {"partition", (PyCFunction)unicode_partition, METH_O, unicode_partition__doc__}, + +PyDoc_STRVAR(unicode_rpartition__doc__, +"rpartition($self, sep, /)\n" +"--\n" +"\n" +"Partition the string into three parts using the given separator.\n" +"\n" +"This will search for the separator in the string, starting and the end. If\n" +"the separator is found, returns a 3-tuple containing the part before the\n" +"separator, the separator itself, and the part after it.\n" +"\n" +"If the separator is not found, returns a 3-tuple containing two empty strings\n" +"and the original string."); + +#define UNICODE_RPARTITION_METHODDEF \ + {"rpartition", (PyCFunction)unicode_rpartition, METH_O, unicode_rpartition__doc__}, + +PyDoc_STRVAR(unicode_rsplit__doc__, +"rsplit($self, /, sep=None, maxsplit=-1)\n" +"--\n" +"\n" +"Return a list of the words in the string, using sep as the delimiter string.\n" +"\n" +" sep\n" +" The delimiter according which to split the string.\n" +" None (the default value) means split according to any whitespace,\n" +" and discard empty strings from the result.\n" +" maxsplit\n" +" Maximum number of splits to do.\n" +" -1 (the default value) means no limit.\n" +"\n" +"Splits are done starting at the end of the string and working to the front."); + +#define UNICODE_RSPLIT_METHODDEF \ + {"rsplit", (PyCFunction)unicode_rsplit, METH_FASTCALL, unicode_rsplit__doc__}, + +static PyObject * +unicode_rsplit_impl(PyObject *self, PyObject *sep, Py_ssize_t maxsplit); + +static PyObject * +unicode_rsplit(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"sep", "maxsplit", NULL}; + static _PyArg_Parser _parser = {"|On:rsplit", _keywords, 0}; + PyObject *sep = Py_None; + Py_ssize_t maxsplit = -1; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &sep, &maxsplit)) { + goto exit; + } + return_value = unicode_rsplit_impl(self, sep, maxsplit); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_splitlines__doc__, +"splitlines($self, /, keepends=False)\n" +"--\n" +"\n" +"Return a list of the lines in the string, breaking at line boundaries.\n" +"\n" +"Line breaks are not included in the resulting list unless keepends is given and\n" +"true."); + +#define UNICODE_SPLITLINES_METHODDEF \ + {"splitlines", (PyCFunction)unicode_splitlines, METH_FASTCALL, unicode_splitlines__doc__}, + +static PyObject * +unicode_splitlines_impl(PyObject *self, int keepends); + +static PyObject * +unicode_splitlines(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"keepends", NULL}; + static _PyArg_Parser _parser = {"|i:splitlines", _keywords, 0}; + int keepends = 0; + + if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + &keepends)) { + goto exit; + } + return_value = unicode_splitlines_impl(self, keepends); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_swapcase__doc__, +"swapcase($self, /)\n" +"--\n" +"\n" +"Convert uppercase characters to lowercase and lowercase characters to uppercase."); + +#define UNICODE_SWAPCASE_METHODDEF \ + {"swapcase", (PyCFunction)unicode_swapcase, METH_NOARGS, unicode_swapcase__doc__}, + +static PyObject * +unicode_swapcase_impl(PyObject *self); + +static PyObject * +unicode_swapcase(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_swapcase_impl(self); +} + PyDoc_STRVAR(unicode_maketrans__doc__, "maketrans(x, y=None, z=None, /)\n" "--\n" @@ -39,4 +823,113 @@ unicode_maketrans(void *null, PyObject *args) exit: return return_value; } -/*[clinic end generated code: output=4a86dd108d92d104 input=a9049054013a1b77]*/ + +PyDoc_STRVAR(unicode_translate__doc__, +"translate($self, table, /)\n" +"--\n" +"\n" +"Replace each character in the string using the given translation table.\n" +"\n" +" table\n" +" Translation table, which must be a mapping of Unicode ordinals to\n" +" Unicode ordinals, strings, or None.\n" +"\n" +"The table must implement lookup/indexing via __getitem__, for instance a\n" +"dictionary or list. If this operation raises LookupError, the character is\n" +"left untouched. Characters mapped to None are deleted."); + +#define UNICODE_TRANSLATE_METHODDEF \ + {"translate", (PyCFunction)unicode_translate, METH_O, unicode_translate__doc__}, + +PyDoc_STRVAR(unicode_upper__doc__, +"upper($self, /)\n" +"--\n" +"\n" +"Return a copy of the string converted to uppercase."); + +#define UNICODE_UPPER_METHODDEF \ + {"upper", (PyCFunction)unicode_upper, METH_NOARGS, unicode_upper__doc__}, + +static PyObject * +unicode_upper_impl(PyObject *self); + +static PyObject * +unicode_upper(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_upper_impl(self); +} + +PyDoc_STRVAR(unicode_zfill__doc__, +"zfill($self, width, /)\n" +"--\n" +"\n" +"Pad a numeric string with zeros on the left, to fill a field of the given width.\n" +"\n" +"The original string is never truncated."); + +#define UNICODE_ZFILL_METHODDEF \ + {"zfill", (PyCFunction)unicode_zfill, METH_O, unicode_zfill__doc__}, + +static PyObject * +unicode_zfill_impl(PyObject *self, Py_ssize_t width); + +static PyObject * +unicode_zfill(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_ssize_t width; + + if (!PyArg_Parse(arg, "n:zfill", &width)) { + goto exit; + } + return_value = unicode_zfill_impl(self, width); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode___format____doc__, +"__format__($self, format_spec, /)\n" +"--\n" +"\n" +"Return a formatted version of S as described by format_spec."); + +#define UNICODE___FORMAT___METHODDEF \ + {"__format__", (PyCFunction)unicode___format__, METH_O, unicode___format____doc__}, + +static PyObject * +unicode___format___impl(PyObject *self, PyObject *format_spec); + +static PyObject * +unicode___format__(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *format_spec; + + if (!PyArg_Parse(arg, "U:__format__", &format_spec)) { + goto exit; + } + return_value = unicode___format___impl(self, format_spec); + +exit: + return return_value; +} + +PyDoc_STRVAR(unicode_sizeof__doc__, +"__sizeof__($self, /)\n" +"--\n" +"\n" +"Return the size of the string in memory, in bytes."); + +#define UNICODE_SIZEOF_METHODDEF \ + {"__sizeof__", (PyCFunction)unicode_sizeof, METH_NOARGS, unicode_sizeof__doc__}, + +static PyObject * +unicode_sizeof_impl(PyObject *self); + +static PyObject * +unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return unicode_sizeof_impl(self); +} +/*[clinic end generated code: output=11b54b7b810af538 input=a9049054013a1b77]*/ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index e322c0cf25..acf59e4d13 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -51,7 +51,21 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /*[clinic input] class str "PyUnicodeObject *" "&PyUnicode_Type" [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=604e916854800fa8]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4884c934de622cf6]*/ + +/*[python input] +class Py_UCS4_converter(CConverter): + type = 'Py_UCS4' + converter = 'convert_uc' + + def converter_init(self): + if self.default is not unspecified: + self.c_default = ascii(self.default) + if len(self.c_default) > 4 or self.c_default[0] != "'": + self.c_default = hex(ord(self.default)) + +[python start generated code]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=88f5dd06cd8e7a61]*/ /* --- Globals ------------------------------------------------------------ @@ -299,6 +313,8 @@ static const unsigned char ascii_linebreak[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static int convert_uc(PyObject *obj, void *addr); + #include "clinic/unicodeobject.c.h" typedef enum { @@ -10710,28 +10726,36 @@ replace(PyObject *self, PyObject *str1, /* --- Unicode Object Methods --------------------------------------------- */ -PyDoc_STRVAR(title__doc__, - "S.title() -> str\n\ -\n\ -Return a titlecased version of S, i.e. words start with title case\n\ -characters, all remaining cased characters have lower case."); +/*[clinic input] +str.title as unicode_title -static PyObject* -unicode_title(PyObject *self) +Return a version of the string where each word is titlecased. + +More specifically, words start with uppercased characters and all remaining +cased characters have lower case. +[clinic start generated code]*/ + +static PyObject * +unicode_title_impl(PyObject *self) +/*[clinic end generated code: output=c75ae03809574902 input=4eb12c1bb8642cb9]*/ { if (PyUnicode_READY(self) == -1) return NULL; return case_operation(self, do_title); } -PyDoc_STRVAR(capitalize__doc__, - "S.capitalize() -> str\n\ -\n\ -Return a capitalized version of S, i.e. make the first character\n\ -have upper case and the rest lower case."); +/*[clinic input] +str.capitalize as unicode_capitalize -static PyObject* -unicode_capitalize(PyObject *self) +Return a capitalized version of the string. + +More specifically, make the first character have upper case and the rest lower +case. +[clinic start generated code]*/ + +static PyObject * +unicode_capitalize_impl(PyObject *self) +/*[clinic end generated code: output=e49a4c333cdb7667 input=f4cbf1016938da6d]*/ { if (PyUnicode_READY(self) == -1) return NULL; @@ -10740,13 +10764,15 @@ unicode_capitalize(PyObject *self) return case_operation(self, do_capitalize); } -PyDoc_STRVAR(casefold__doc__, - "S.casefold() -> str\n\ -\n\ -Return a version of S suitable for caseless comparisons."); +/*[clinic input] +str.casefold as unicode_casefold + +Return a version of the string suitable for caseless comparisons. +[clinic start generated code]*/ static PyObject * -unicode_casefold(PyObject *self) +unicode_casefold_impl(PyObject *self) +/*[clinic end generated code: output=0120daf657ca40af input=a96f2b0d3daabd94]*/ { if (PyUnicode_READY(self) == -1) return NULL; @@ -10780,21 +10806,23 @@ convert_uc(PyObject *obj, void *addr) return 1; } -PyDoc_STRVAR(center__doc__, - "S.center(width[, fillchar]) -> str\n\ -\n\ -Return S centered in a string of length width. Padding is\n\ -done using the specified fill character (default is a space)"); +/*[clinic input] +str.center as unicode_center + + width: Py_ssize_t + fillchar: Py_UCS4 = ' ' + / + +Return a centered string of length width. + +Padding is done using the specified fill character (default is a space). +[clinic start generated code]*/ static PyObject * -unicode_center(PyObject *self, PyObject *args) +unicode_center_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar) +/*[clinic end generated code: output=420c8859effc7c0c input=b42b247eb26e6519]*/ { Py_ssize_t marg, left; - Py_ssize_t width; - Py_UCS4 fillchar = ' '; - - if (!PyArg_ParseTuple(args, "n|O&:center", &width, convert_uc, &fillchar)) - return NULL; if (PyUnicode_READY(self) == -1) return NULL; @@ -11465,51 +11493,49 @@ unicode_count(PyObject *self, PyObject *args) return result; } -PyDoc_STRVAR(encode__doc__, - "S.encode(encoding='utf-8', errors='strict') -> bytes\n\ -\n\ -Encode S using the codec registered for encoding. Default encoding\n\ -is 'utf-8'. errors may be given to set a different error\n\ -handling scheme. Default is 'strict' meaning that encoding errors raise\n\ -a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and\n\ -'xmlcharrefreplace' as well as any other name registered with\n\ -codecs.register_error that can handle UnicodeEncodeErrors."); +/*[clinic input] +str.encode as unicode_encode + + encoding: str(c_default="NULL") = 'utf-8' + The encoding in which to encode the string. + errors: str(c_default="NULL") = 'strict' + The error handling scheme to use for encoding errors. + The default is 'strict' meaning that encoding errors raise a + UnicodeEncodeError. Other possible values are 'ignore', 'replace' and + 'xmlcharrefreplace' as well as any other name registered with + codecs.register_error that can handle UnicodeEncodeErrors. + +Encode the string using the codec registered for encoding. +[clinic start generated code]*/ static PyObject * -unicode_encode(PyObject *self, PyObject *args, PyObject *kwargs) +unicode_encode_impl(PyObject *self, const char *encoding, const char *errors) +/*[clinic end generated code: output=bf78b6e2a9470e3c input=12fcb2e5798e96dc]*/ { - static char *kwlist[] = {"encoding", "errors", 0}; - char *encoding = NULL; - char *errors = NULL; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ss:encode", - kwlist, &encoding, &errors)) - return NULL; return PyUnicode_AsEncodedString(self, encoding, errors); } -PyDoc_STRVAR(expandtabs__doc__, - "S.expandtabs(tabsize=8) -> str\n\ -\n\ -Return a copy of S where all tab characters are expanded using spaces.\n\ -If tabsize is not given, a tab size of 8 characters is assumed."); +/*[clinic input] +str.expandtabs as unicode_expandtabs -static PyObject* -unicode_expandtabs(PyObject *self, PyObject *args, PyObject *kwds) + tabsize: int = 8 + +Return a copy where all tab characters are expanded using spaces. + +If tabsize is not given, a tab size of 8 characters is assumed. +[clinic start generated code]*/ + +static PyObject * +unicode_expandtabs_impl(PyObject *self, int tabsize) +/*[clinic end generated code: output=3457c5dcee26928f input=8a01914034af4c85]*/ { Py_ssize_t i, j, line_pos, src_len, incr; Py_UCS4 ch; PyObject *u; void *src_data, *dest_data; - static char *kwlist[] = {"tabsize", 0}; - int tabsize = 8; int kind; int found; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:expandtabs", - kwlist, &tabsize)) - return NULL; - if (PyUnicode_READY(self) == -1) return NULL; @@ -11693,14 +11719,18 @@ unicode_index(PyObject *self, PyObject *args) return PyLong_FromSsize_t(result); } -PyDoc_STRVAR(islower__doc__, - "S.islower() -> bool\n\ -\n\ -Return True if all cased characters in S are lowercase and there is\n\ -at least one cased character in S, False otherwise."); +/*[clinic input] +str.islower as unicode_islower -static PyObject* -unicode_islower(PyObject *self) +Return True if the string is a lowercase string, False otherwise. + +A string is lowercase if all cased characters in the string are lowercase and +there is at least one cased character in the string. +[clinic start generated code]*/ + +static PyObject * +unicode_islower_impl(PyObject *self) +/*[clinic end generated code: output=dbd41995bd005b81 input=46eeb20d935af050]*/ { Py_ssize_t i, length; int kind; @@ -11734,14 +11764,18 @@ unicode_islower(PyObject *self) return PyBool_FromLong(cased); } -PyDoc_STRVAR(isupper__doc__, - "S.isupper() -> bool\n\ -\n\ -Return True if all cased characters in S are uppercase and there is\n\ -at least one cased character in S, False otherwise."); +/*[clinic input] +str.isupper as unicode_isupper -static PyObject* -unicode_isupper(PyObject *self) +Return True if the string is an uppercase string, False otherwise. + +A string is uppercase if all cased characters in the string are uppercase and +there is at least one cased character in the string. +[clinic start generated code]*/ + +static PyObject * +unicode_isupper_impl(PyObject *self) +/*[clinic end generated code: output=049209c8e7f15f59 input=dd0a595fc871eee0]*/ { Py_ssize_t i, length; int kind; @@ -11775,16 +11809,18 @@ unicode_isupper(PyObject *self) return PyBool_FromLong(cased); } -PyDoc_STRVAR(istitle__doc__, - "S.istitle() -> bool\n\ -\n\ -Return True if S is a titlecased string and there is at least one\n\ -character in S, i.e. upper- and titlecase characters may only\n\ -follow uncased characters and lowercase characters only cased ones.\n\ -Return False otherwise."); +/*[clinic input] +str.istitle as unicode_istitle -static PyObject* -unicode_istitle(PyObject *self) +Return True if the string is a title-cased string, False otherwise. + +In a title-cased string, upper- and title-case characters may only +follow uncased characters and lowercase characters only cased ones. +[clinic start generated code]*/ + +static PyObject * +unicode_istitle_impl(PyObject *self) +/*[clinic end generated code: output=e9bf6eb91f5d3f0e input=2c56883d113d644d]*/ { Py_ssize_t i, length; int kind; @@ -11831,14 +11867,18 @@ unicode_istitle(PyObject *self) return PyBool_FromLong(cased); } -PyDoc_STRVAR(isspace__doc__, - "S.isspace() -> bool\n\ -\n\ -Return True if all characters in S are whitespace\n\ -and there is at least one character in S, False otherwise."); +/*[clinic input] +str.isspace as unicode_isspace -static PyObject* -unicode_isspace(PyObject *self) +Return True if the string is a whitespace string, False otherwise. + +A string is whitespace if all characters in the string are whitespace and there +is at least one character in the string. +[clinic start generated code]*/ + +static PyObject * +unicode_isspace_impl(PyObject *self) +/*[clinic end generated code: output=163a63bfa08ac2b9 input=b9506a23e312d203]*/ { Py_ssize_t i, length; int kind; @@ -11867,14 +11907,18 @@ unicode_isspace(PyObject *self) return PyBool_FromLong(1); } -PyDoc_STRVAR(isalpha__doc__, - "S.isalpha() -> bool\n\ -\n\ -Return True if all characters in S are alphabetic\n\ -and there is at least one character in S, False otherwise."); +/*[clinic input] +str.isalpha as unicode_isalpha -static PyObject* -unicode_isalpha(PyObject *self) +Return True if the string is an alphabetic string, False otherwise. + +A string is alphabetic if all characters in the string are alphabetic and there +is at least one character in the string. +[clinic start generated code]*/ + +static PyObject * +unicode_isalpha_impl(PyObject *self) +/*[clinic end generated code: output=cc81b9ac3883ec4f input=17e3788814472079]*/ { Py_ssize_t i, length; int kind; @@ -11902,14 +11946,18 @@ unicode_isalpha(PyObject *self) return PyBool_FromLong(1); } -PyDoc_STRVAR(isalnum__doc__, - "S.isalnum() -> bool\n\ -\n\ -Return True if all characters in S are alphanumeric\n\ -and there is at least one character in S, False otherwise."); +/*[clinic input] +str.isalnum as unicode_isalnum -static PyObject* -unicode_isalnum(PyObject *self) +Return True if the string is an alpha-numeric string, False otherwise. + +A string is alpha-numeric if all characters in the string are alpha-numeric and +there is at least one character in the string. +[clinic start generated code]*/ + +static PyObject * +unicode_isalnum_impl(PyObject *self) +/*[clinic end generated code: output=a5a23490ffc3660c input=d350c4f7c59b4758]*/ { int kind; void *data; @@ -11940,14 +11988,18 @@ unicode_isalnum(PyObject *self) return PyBool_FromLong(1); } -PyDoc_STRVAR(isdecimal__doc__, - "S.isdecimal() -> bool\n\ -\n\ -Return True if there are only decimal characters in S,\n\ -False otherwise."); +/*[clinic input] +str.isdecimal as unicode_isdecimal -static PyObject* -unicode_isdecimal(PyObject *self) +Return True if the string is a decimal string, False otherwise. + +A string is a decimal string if all characters in the string are decimal and +there is at least one character in the string. +[clinic start generated code]*/ + +static PyObject * +unicode_isdecimal_impl(PyObject *self) +/*[clinic end generated code: output=fb2dcdb62d3fc548 input=40536fb80e5f1dc1]*/ { Py_ssize_t i, length; int kind; @@ -11975,14 +12027,18 @@ unicode_isdecimal(PyObject *self) return PyBool_FromLong(1); } -PyDoc_STRVAR(isdigit__doc__, - "S.isdigit() -> bool\n\ -\n\ -Return True if all characters in S are digits\n\ -and there is at least one character in S, False otherwise."); +/*[clinic input] +str.isdigit as unicode_isdigit -static PyObject* -unicode_isdigit(PyObject *self) +Return True if the string is a digit string, False otherwise. + +A string is a digit string if all characters in the string are digits and there +is at least one character in the string. +[clinic start generated code]*/ + +static PyObject * +unicode_isdigit_impl(PyObject *self) +/*[clinic end generated code: output=10a6985311da6858 input=c6a222be1aaec2af]*/ { Py_ssize_t i, length; int kind; @@ -12011,14 +12067,18 @@ unicode_isdigit(PyObject *self) return PyBool_FromLong(1); } -PyDoc_STRVAR(isnumeric__doc__, - "S.isnumeric() -> bool\n\ -\n\ -Return True if there are only numeric characters in S,\n\ -False otherwise."); +/*[clinic input] +str.isnumeric as unicode_isnumeric -static PyObject* -unicode_isnumeric(PyObject *self) +Return True if the string is a numeric string, False otherwise. + +A string is numeric if all characters in the string are numeric and there is at +least one character in the string. +[clinic start generated code]*/ + +static PyObject * +unicode_isnumeric_impl(PyObject *self) +/*[clinic end generated code: output=9172a32d9013051a input=e3b37b2cc8854f35]*/ { Py_ssize_t i, length; int kind; @@ -12083,29 +12143,34 @@ PyUnicode_IsIdentifier(PyObject *self) return 1; } -PyDoc_STRVAR(isidentifier__doc__, - "S.isidentifier() -> bool\n\ -\n\ -Return True if S is a valid identifier according\n\ -to the language definition.\n\ -\n\ -Use keyword.iskeyword() to test for reserved identifiers\n\ -such as \"def\" and \"class\".\n"); +/*[clinic input] +str.isidentifier as unicode_isidentifier -static PyObject* -unicode_isidentifier(PyObject *self) +Return True if the string is a valid Python identifier, False otherwise. + +Use keyword.iskeyword() to test for reserved identifiers such as "def" and +"class". +[clinic start generated code]*/ + +static PyObject * +unicode_isidentifier_impl(PyObject *self) +/*[clinic end generated code: output=fe585a9666572905 input=95eebe40d6d91234]*/ { return PyBool_FromLong(PyUnicode_IsIdentifier(self)); } -PyDoc_STRVAR(isprintable__doc__, - "S.isprintable() -> bool\n\ -\n\ -Return True if all characters in S are considered\n\ -printable in repr() or S is empty, False otherwise."); +/*[clinic input] +str.isprintable as unicode_isprintable -static PyObject* -unicode_isprintable(PyObject *self) +Return True if the string is printable, False otherwise. + +A string is printable if all of its characters are considered printable in +repr() or if it is empty. +[clinic start generated code]*/ + +static PyObject * +unicode_isprintable_impl(PyObject *self) +/*[clinic end generated code: output=3ab9626cd32dd1a0 input=20c53134171af84e]*/ { Py_ssize_t i, length; int kind; @@ -12130,16 +12195,25 @@ unicode_isprintable(PyObject *self) Py_RETURN_TRUE; } -PyDoc_STRVAR(join__doc__, - "S.join(iterable) -> str\n\ -\n\ -Return a string which is the concatenation of the strings in the\n\ -iterable. The separator between elements is S."); +/*[clinic input] +str.join as unicode_join -static PyObject* -unicode_join(PyObject *self, PyObject *data) + iterable: object + / + +Concatenate any number of strings. + +The string whose method is called is inserted in between each given strings. +The result is returned as a new string. + +Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs' +[clinic start generated code]*/ + +static PyObject * +unicode_join(PyObject *self, PyObject *iterable) +/*[clinic end generated code: output=6857e7cecfe7bf98 input=465f62626109db6b]*/ { - return PyUnicode_Join(self, data); + return PyUnicode_Join(self, iterable); } static Py_ssize_t @@ -12150,21 +12224,22 @@ unicode_length(PyObject *self) return PyUnicode_GET_LENGTH(self); } -PyDoc_STRVAR(ljust__doc__, - "S.ljust(width[, fillchar]) -> str\n\ -\n\ -Return S left-justified in a Unicode string of length width. Padding is\n\ -done using the specified fill character (default is a space)."); +/*[clinic input] +str.ljust as unicode_ljust -static PyObject * -unicode_ljust(PyObject *self, PyObject *args) -{ - Py_ssize_t width; - Py_UCS4 fillchar = ' '; + width: Py_ssize_t + fillchar: Py_UCS4 = ' ' + / - if (!PyArg_ParseTuple(args, "n|O&:ljust", &width, convert_uc, &fillchar)) - return NULL; +Return a left-justified string of length width. +Padding is done using the specified fill character (default is a space). +[clinic start generated code]*/ + +static PyObject * +unicode_ljust_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar) +/*[clinic end generated code: output=1cce0e0e0a0b84b3 input=3ab599e335e60a32]*/ +{ if (PyUnicode_READY(self) == -1) return NULL; @@ -12174,13 +12249,15 @@ unicode_ljust(PyObject *self, PyObject *args) return pad(self, 0, width - PyUnicode_GET_LENGTH(self), fillchar); } -PyDoc_STRVAR(lower__doc__, - "S.lower() -> str\n\ -\n\ -Return a copy of the string S converted to lowercase."); +/*[clinic input] +str.lower as unicode_lower -static PyObject* -unicode_lower(PyObject *self) +Return a copy of the string converted to lowercase. +[clinic start generated code]*/ + +static PyObject * +unicode_lower_impl(PyObject *self) +/*[clinic end generated code: output=84ef9ed42efad663 input=60a2984b8beff23a]*/ { if (PyUnicode_READY(self) == -1) return NULL; @@ -12194,9 +12271,9 @@ unicode_lower(PyObject *self) #define BOTHSTRIP 2 /* Arrays indexed by above */ -static const char * const stripformat[] = {"|O:lstrip", "|O:rstrip", "|O:strip"}; +static const char *stripfuncnames[] = {"lstrip", "rstrip", "strip"}; -#define STRIPNAME(i) (stripformat[i]+3) +#define STRIPNAME(i) (stripfuncnames[i]) /* externally visible for str.strip(unicode) */ PyObject * @@ -12353,13 +12430,8 @@ do_strip(PyObject *self, int striptype) static PyObject * -do_argstrip(PyObject *self, int striptype, PyObject *args) +do_argstrip(PyObject *self, int striptype, PyObject *sep) { - PyObject *sep = NULL; - - if (!PyArg_ParseTuple(args, stripformat[striptype], &sep)) - return NULL; - if (sep != NULL && sep != Py_None) { if (PyUnicode_Check(sep)) return _PyUnicode_XStrip(self, striptype, sep); @@ -12375,52 +12447,60 @@ do_argstrip(PyObject *self, int striptype, PyObject *args) } -PyDoc_STRVAR(strip__doc__, - "S.strip([chars]) -> str\n\ -\n\ -Return a copy of the string S with leading and trailing\n\ -whitespace removed.\n\ -If chars is given and not None, remove characters in chars instead."); +/*[clinic input] +str.strip as unicode_strip + + chars: object = None + / + +Return a copy of the string with leading and trailing whitespace removed. + +If chars is given and not None, remove characters in chars instead. +[clinic start generated code]*/ static PyObject * -unicode_strip(PyObject *self, PyObject *args) +unicode_strip_impl(PyObject *self, PyObject *chars) +/*[clinic end generated code: output=ca19018454345d57 input=385289c6f423b954]*/ { - if (PyTuple_GET_SIZE(args) == 0) - return do_strip(self, BOTHSTRIP); /* Common case */ - else - return do_argstrip(self, BOTHSTRIP, args); + return do_argstrip(self, BOTHSTRIP, chars); } -PyDoc_STRVAR(lstrip__doc__, - "S.lstrip([chars]) -> str\n\ -\n\ -Return a copy of the string S with leading whitespace removed.\n\ -If chars is given and not None, remove characters in chars instead."); +/*[clinic input] +str.lstrip as unicode_lstrip + + chars: object = NULL + / + +Return a copy of the string with leading whitespace removed. + +If chars is given and not None, remove characters in chars instead. +[clinic start generated code]*/ static PyObject * -unicode_lstrip(PyObject *self, PyObject *args) +unicode_lstrip_impl(PyObject *self, PyObject *chars) +/*[clinic end generated code: output=3b43683251f79ca7 input=9e56f3c45f5ff4c3]*/ { - if (PyTuple_GET_SIZE(args) == 0) - return do_strip(self, LEFTSTRIP); /* Common case */ - else - return do_argstrip(self, LEFTSTRIP, args); + return do_argstrip(self, LEFTSTRIP, chars); } -PyDoc_STRVAR(rstrip__doc__, - "S.rstrip([chars]) -> str\n\ -\n\ -Return a copy of the string S with trailing whitespace removed.\n\ -If chars is given and not None, remove characters in chars instead."); +/*[clinic input] +str.rstrip as unicode_rstrip + + chars: object = NULL + / + +Return a copy of the string with trailing whitespace removed. + +If chars is given and not None, remove characters in chars instead. +[clinic start generated code]*/ static PyObject * -unicode_rstrip(PyObject *self, PyObject *args) +unicode_rstrip_impl(PyObject *self, PyObject *chars) +/*[clinic end generated code: output=4a59230017cc3b7a input=ac89d0219cb411ee]*/ { - if (PyTuple_GET_SIZE(args) == 0) - return do_strip(self, RIGHTSTRIP); /* Common case */ - else - return do_argstrip(self, RIGHTSTRIP, args); + return do_argstrip(self, RIGHTSTRIP, chars); } @@ -12500,25 +12580,30 @@ PyUnicode_Replace(PyObject *str, return replace(str, substr, replstr, maxcount); } -PyDoc_STRVAR(replace__doc__, - "S.replace(old, new[, count]) -> str\n\ -\n\ -Return a copy of S with all occurrences of substring\n\ -old replaced by new. If the optional argument count is\n\ -given, only the first count occurrences are replaced."); +/*[clinic input] +str.replace as unicode_replace -static PyObject* -unicode_replace(PyObject *self, PyObject *args) -{ - PyObject *str1; - PyObject *str2; - Py_ssize_t maxcount = -1; + old: unicode + new: unicode + count: Py_ssize_t = -1 + Maximum number of occurrences to replace. + -1 (the default value) means replace all occurrences. + / - if (!PyArg_ParseTuple(args, "UU|n:replace", &str1, &str2, &maxcount)) - return NULL; +Return a copy with all occurrences of substring old replaced by new. + +If the optional argument count is given, only the first count occurrences are +replaced. +[clinic start generated code]*/ + +static PyObject * +unicode_replace_impl(PyObject *self, PyObject *old, PyObject *new, + Py_ssize_t count) +/*[clinic end generated code: output=b63f1a8b5eebf448 input=147d12206276ebeb]*/ +{ if (PyUnicode_READY(self) == -1) return NULL; - return replace(self, str1, str2, maxcount); + return replace(self, old, new, count); } static PyObject * @@ -12750,21 +12835,22 @@ unicode_rindex(PyObject *self, PyObject *args) return PyLong_FromSsize_t(result); } -PyDoc_STRVAR(rjust__doc__, - "S.rjust(width[, fillchar]) -> str\n\ -\n\ -Return S right-justified in a string of length width. Padding is\n\ -done using the specified fill character (default is a space)."); +/*[clinic input] +str.rjust as unicode_rjust -static PyObject * -unicode_rjust(PyObject *self, PyObject *args) -{ - Py_ssize_t width; - Py_UCS4 fillchar = ' '; + width: Py_ssize_t + fillchar: Py_UCS4 = ' ' + / - if (!PyArg_ParseTuple(args, "n|O&:rjust", &width, convert_uc, &fillchar)) - return NULL; +Return a right-justified string of length width. + +Padding is done using the specified fill character (default is a space). +[clinic start generated code]*/ +static PyObject * +unicode_rjust_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar) +/*[clinic end generated code: output=804a1a57fbe8d5cf input=d05f550b5beb1f72]*/ +{ if (PyUnicode_READY(self) == -1) return NULL; @@ -12783,35 +12869,32 @@ PyUnicode_Split(PyObject *s, PyObject *sep, Py_ssize_t maxsplit) return split(s, sep, maxsplit); } -PyDoc_STRVAR(split__doc__, - "S.split(sep=None, maxsplit=-1) -> list of strings\n\ -\n\ -Return a list of the words in S, using sep as the\n\ -delimiter string. If maxsplit is given, at most maxsplit\n\ -splits are done. If sep is not specified or is None, any\n\ -whitespace string is a separator and empty strings are\n\ -removed from the result."); - -static PyObject* -unicode_split(PyObject *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"sep", "maxsplit", 0}; - PyObject *substring = Py_None; - Py_ssize_t maxcount = -1; +/*[clinic input] +str.split as unicode_split - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|On:split", - kwlist, &substring, &maxcount)) - return NULL; + sep: object = None + The delimiter according which to split the string. + None (the default value) means split according to any whitespace, + and discard empty strings from the result. + maxsplit: Py_ssize_t = -1 + Maximum number of splits to do. + -1 (the default value) means no limit. - if (substring == Py_None) - return split(self, NULL, maxcount); +Return a list of the words in the string, using sep as the delimiter string. +[clinic start generated code]*/ - if (PyUnicode_Check(substring)) - return split(self, substring, maxcount); +static PyObject * +unicode_split_impl(PyObject *self, PyObject *sep, Py_ssize_t maxsplit) +/*[clinic end generated code: output=3a65b1db356948dc input=606e750488a82359]*/ +{ + if (sep == Py_None) + return split(self, NULL, maxsplit); + if (PyUnicode_Check(sep)) + return split(self, sep, maxsplit); PyErr_Format(PyExc_TypeError, "must be str or None, not %.100s", - Py_TYPE(substring)->tp_name); + Py_TYPE(sep)->tp_name); return NULL; } @@ -12930,30 +13013,47 @@ PyUnicode_RPartition(PyObject *str_obj, PyObject *sep_obj) return out; } -PyDoc_STRVAR(partition__doc__, - "S.partition(sep) -> (head, sep, tail)\n\ -\n\ -Search for the separator sep in S, and return the part before it,\n\ -the separator itself, and the part after it. If the separator is not\n\ -found, return S and two empty strings."); +/*[clinic input] +str.partition as unicode_partition -static PyObject* -unicode_partition(PyObject *self, PyObject *separator) + sep: object + / + +Partition the string into three parts using the given separator. + +This will search for the separator in the string. If the separator is found, +returns a 3-tuple containing the part before the separator, the separator +itself, and the part after it. + +If the separator is not found, returns a 3-tuple containing the original string +and two empty strings. +[clinic start generated code]*/ + +static PyObject * +unicode_partition(PyObject *self, PyObject *sep) +/*[clinic end generated code: output=e4ced7bd253ca3c4 input=f29b8d06c63e50be]*/ { - return PyUnicode_Partition(self, separator); + return PyUnicode_Partition(self, sep); } -PyDoc_STRVAR(rpartition__doc__, - "S.rpartition(sep) -> (head, sep, tail)\n\ -\n\ -Search for the separator sep in S, starting at the end of S, and return\n\ -the part before it, the separator itself, and the part after it. If the\n\ -separator is not found, return two empty strings and S."); +/*[clinic input] +str.rpartition as unicode_rpartition = str.partition -static PyObject* -unicode_rpartition(PyObject *self, PyObject *separator) +Partition the string into three parts using the given separator. + +This will search for the separator in the string, starting and the end. If +the separator is found, returns a 3-tuple containing the part before the +separator, the separator itself, and the part after it. + +If the separator is not found, returns a 3-tuple containing two empty strings +and the original string. +[clinic start generated code]*/ + +static PyObject * +unicode_rpartition(PyObject *self, PyObject *sep) +/*[clinic end generated code: output=1aa13cf1156572aa input=e77c7acb69bdfca6]*/ { - return PyUnicode_RPartition(self, separator); + return PyUnicode_RPartition(self, sep); } PyObject * @@ -12965,55 +13065,44 @@ PyUnicode_RSplit(PyObject *s, PyObject *sep, Py_ssize_t maxsplit) return rsplit(s, sep, maxsplit); } -PyDoc_STRVAR(rsplit__doc__, - "S.rsplit(sep=None, maxsplit=-1) -> list of strings\n\ -\n\ -Return a list of the words in S, using sep as the\n\ -delimiter string, starting at the end of the string and\n\ -working to the front. If maxsplit is given, at most maxsplit\n\ -splits are done. If sep is not specified, any whitespace string\n\ -is a separator."); - -static PyObject* -unicode_rsplit(PyObject *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"sep", "maxsplit", 0}; - PyObject *substring = Py_None; - Py_ssize_t maxcount = -1; +/*[clinic input] +str.rsplit as unicode_rsplit = str.split - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|On:rsplit", - kwlist, &substring, &maxcount)) - return NULL; +Return a list of the words in the string, using sep as the delimiter string. - if (substring == Py_None) - return rsplit(self, NULL, maxcount); +Splits are done starting at the end of the string and working to the front. +[clinic start generated code]*/ - if (PyUnicode_Check(substring)) - return rsplit(self, substring, maxcount); +static PyObject * +unicode_rsplit_impl(PyObject *self, PyObject *sep, Py_ssize_t maxsplit) +/*[clinic end generated code: output=c2b815c63bcabffc input=12ad4bf57dd35f15]*/ +{ + if (sep == Py_None) + return rsplit(self, NULL, maxsplit); + if (PyUnicode_Check(sep)) + return rsplit(self, sep, maxsplit); PyErr_Format(PyExc_TypeError, "must be str or None, not %.100s", - Py_TYPE(substring)->tp_name); + Py_TYPE(sep)->tp_name); return NULL; } -PyDoc_STRVAR(splitlines__doc__, - "S.splitlines([keepends]) -> list of strings\n\ -\n\ -Return a list of the lines in S, breaking at line boundaries.\n\ -Line breaks are not included in the resulting list unless keepends\n\ -is given and true."); +/*[clinic input] +str.splitlines as unicode_splitlines -static PyObject* -unicode_splitlines(PyObject *self, PyObject *args, PyObject *kwds) -{ - static char *kwlist[] = {"keepends", 0}; - int keepends = 0; + keepends: int(c_default="0") = False - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:splitlines", - kwlist, &keepends)) - return NULL; +Return a list of the lines in the string, breaking at line boundaries. + +Line breaks are not included in the resulting list unless keepends is given and +true. +[clinic start generated code]*/ +static PyObject * +unicode_splitlines_impl(PyObject *self, int keepends) +/*[clinic end generated code: output=f664dcdad153ec40 input=d6ff99fe43465b0f]*/ +{ return PyUnicode_Splitlines(self, keepends); } @@ -13023,14 +13112,15 @@ PyObject *unicode_str(PyObject *self) return unicode_result_unchanged(self); } -PyDoc_STRVAR(swapcase__doc__, - "S.swapcase() -> str\n\ -\n\ -Return a copy of S with uppercase characters converted to lowercase\n\ -and vice versa."); +/*[clinic input] +str.swapcase as unicode_swapcase -static PyObject* -unicode_swapcase(PyObject *self) +Convert uppercase characters to lowercase and lowercase characters to uppercase. +[clinic start generated code]*/ + +static PyObject * +unicode_swapcase_impl(PyObject *self) +/*[clinic end generated code: output=5d28966bf6d7b2af input=3f3ef96d5798a7bb]*/ { if (PyUnicode_READY(self) == -1) return NULL; @@ -13167,29 +13257,37 @@ unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z) return NULL; } -PyDoc_STRVAR(translate__doc__, - "S.translate(table) -> str\n\ -\n\ -Return a copy of the string S in which each character has been mapped\n\ -through the given translation table. The table must implement\n\ -lookup/indexing via __getitem__, for instance a dictionary or list,\n\ -mapping Unicode ordinals to Unicode ordinals, strings, or None. If\n\ -this operation raises LookupError, the character is left untouched.\n\ -Characters mapped to None are deleted."); +/*[clinic input] +str.translate as unicode_translate -static PyObject* + table: object + Translation table, which must be a mapping of Unicode ordinals to + Unicode ordinals, strings, or None. + / + +Replace each character in the string using the given translation table. + +The table must implement lookup/indexing via __getitem__, for instance a +dictionary or list. If this operation raises LookupError, the character is +left untouched. Characters mapped to None are deleted. +[clinic start generated code]*/ + +static PyObject * unicode_translate(PyObject *self, PyObject *table) +/*[clinic end generated code: output=3cb448ff2fd96bf3 input=6d38343db63d8eb0]*/ { return _PyUnicode_TranslateCharmap(self, table, "ignore"); } -PyDoc_STRVAR(upper__doc__, - "S.upper() -> str\n\ -\n\ -Return a copy of S converted to uppercase."); +/*[clinic input] +str.upper as unicode_upper -static PyObject* -unicode_upper(PyObject *self) +Return a copy of the string converted to uppercase. +[clinic start generated code]*/ + +static PyObject * +unicode_upper_impl(PyObject *self) +/*[clinic end generated code: output=1b7ddd16bbcdc092 input=db3d55682dfe2e6c]*/ { if (PyUnicode_READY(self) == -1) return NULL; @@ -13198,25 +13296,27 @@ unicode_upper(PyObject *self) return case_operation(self, do_upper); } -PyDoc_STRVAR(zfill__doc__, - "S.zfill(width) -> str\n\ -\n\ -Pad a numeric string S with zeros on the left, to fill a field\n\ -of the specified width. The string S is never truncated."); +/*[clinic input] +str.zfill as unicode_zfill + + width: Py_ssize_t + / + +Pad a numeric string with zeros on the left, to fill a field of the given width. + +The string is never truncated. +[clinic start generated code]*/ static PyObject * -unicode_zfill(PyObject *self, PyObject *args) +unicode_zfill_impl(PyObject *self, Py_ssize_t width) +/*[clinic end generated code: output=e13fb6bdf8e3b9df input=3559257ab7bfed6e]*/ { Py_ssize_t fill; PyObject *u; - Py_ssize_t width; int kind; void *data; Py_UCS4 chr; - if (!PyArg_ParseTuple(args, "n:zfill", &width)) - return NULL; - if (PyUnicode_READY(self) == -1) return NULL; @@ -13703,16 +13803,22 @@ PyDoc_STRVAR(format_map__doc__, Return a formatted version of S, using substitutions from mapping.\n\ The substitutions are identified by braces ('{' and '}')."); +/*[clinic input] +str.__format__ as unicode___format__ + + format_spec: unicode + / + +Return a formatted version of the string as described by format_spec. +[clinic start generated code]*/ + static PyObject * -unicode__format__(PyObject* self, PyObject* args) +unicode___format___impl(PyObject *self, PyObject *format_spec) +/*[clinic end generated code: output=45fceaca6d2ba4c8 input=1f0623ca7b7c5981]*/ { - PyObject *format_spec; _PyUnicodeWriter writer; int ret; - if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) - return NULL; - if (PyUnicode_READY(self) == -1) return NULL; _PyUnicodeWriter_Init(&writer); @@ -13726,44 +13832,43 @@ unicode__format__(PyObject* self, PyObject* args) return _PyUnicodeWriter_Finish(&writer); } -PyDoc_STRVAR(p_format__doc__, - "S.__format__(format_spec) -> str\n\ -\n\ -Return a formatted version of S as described by format_spec."); +/*[clinic input] +str.__sizeof__ as unicode_sizeof + +Return the size of the string in memory, in bytes. +[clinic start generated code]*/ static PyObject * -unicode__sizeof__(PyObject *v) +unicode_sizeof_impl(PyObject *self) +/*[clinic end generated code: output=6dbc2f5a408b6d4f input=6dd011c108e33fb0]*/ { Py_ssize_t size; /* If it's a compact object, account for base structure + character data. */ - if (PyUnicode_IS_COMPACT_ASCII(v)) - size = sizeof(PyASCIIObject) + PyUnicode_GET_LENGTH(v) + 1; - else if (PyUnicode_IS_COMPACT(v)) + if (PyUnicode_IS_COMPACT_ASCII(self)) + size = sizeof(PyASCIIObject) + PyUnicode_GET_LENGTH(self) + 1; + else if (PyUnicode_IS_COMPACT(self)) size = sizeof(PyCompactUnicodeObject) + - (PyUnicode_GET_LENGTH(v) + 1) * PyUnicode_KIND(v); + (PyUnicode_GET_LENGTH(self) + 1) * PyUnicode_KIND(self); else { /* If it is a two-block object, account for base object, and for character block if present. */ size = sizeof(PyUnicodeObject); - if (_PyUnicode_DATA_ANY(v)) - size += (PyUnicode_GET_LENGTH(v) + 1) * - PyUnicode_KIND(v); + if (_PyUnicode_DATA_ANY(self)) + size += (PyUnicode_GET_LENGTH(self) + 1) * + PyUnicode_KIND(self); } /* If the wstr pointer is present, account for it unless it is shared with the data pointer. Check if the data is not shared. */ - if (_PyUnicode_HAS_WSTR_MEMORY(v)) - size += (PyUnicode_WSTR_LENGTH(v) + 1) * sizeof(wchar_t); - if (_PyUnicode_HAS_UTF8_MEMORY(v)) - size += PyUnicode_UTF8_LENGTH(v) + 1; + if (_PyUnicode_HAS_WSTR_MEMORY(self)) + size += (PyUnicode_WSTR_LENGTH(self) + 1) * sizeof(wchar_t); + if (_PyUnicode_HAS_UTF8_MEMORY(self)) + size += PyUnicode_UTF8_LENGTH(self) + 1; return PyLong_FromSsize_t(size); } -PyDoc_STRVAR(sizeof__doc__, - "S.__sizeof__() -> size of S in memory, in bytes"); - static PyObject * unicode_getnewargs(PyObject *v) { @@ -13774,54 +13879,52 @@ unicode_getnewargs(PyObject *v) } static PyMethodDef unicode_methods[] = { - {"encode", (PyCFunction) unicode_encode, METH_VARARGS | METH_KEYWORDS, encode__doc__}, - {"replace", (PyCFunction) unicode_replace, METH_VARARGS, replace__doc__}, - {"split", (PyCFunction) unicode_split, METH_VARARGS | METH_KEYWORDS, split__doc__}, - {"rsplit", (PyCFunction) unicode_rsplit, METH_VARARGS | METH_KEYWORDS, rsplit__doc__}, - {"join", (PyCFunction) unicode_join, METH_O, join__doc__}, - {"capitalize", (PyCFunction) unicode_capitalize, METH_NOARGS, capitalize__doc__}, - {"casefold", (PyCFunction) unicode_casefold, METH_NOARGS, casefold__doc__}, - {"title", (PyCFunction) unicode_title, METH_NOARGS, title__doc__}, - {"center", (PyCFunction) unicode_center, METH_VARARGS, center__doc__}, + UNICODE_ENCODE_METHODDEF + UNICODE_REPLACE_METHODDEF + UNICODE_SPLIT_METHODDEF + UNICODE_RSPLIT_METHODDEF + UNICODE_JOIN_METHODDEF + UNICODE_CAPITALIZE_METHODDEF + UNICODE_CASEFOLD_METHODDEF + UNICODE_TITLE_METHODDEF + UNICODE_CENTER_METHODDEF {"count", (PyCFunction) unicode_count, METH_VARARGS, count__doc__}, - {"expandtabs", (PyCFunction) unicode_expandtabs, - METH_VARARGS | METH_KEYWORDS, expandtabs__doc__}, + UNICODE_EXPANDTABS_METHODDEF {"find", (PyCFunction) unicode_find, METH_VARARGS, find__doc__}, - {"partition", (PyCFunction) unicode_partition, METH_O, partition__doc__}, + UNICODE_PARTITION_METHODDEF {"index", (PyCFunction) unicode_index, METH_VARARGS, index__doc__}, - {"ljust", (PyCFunction) unicode_ljust, METH_VARARGS, ljust__doc__}, - {"lower", (PyCFunction) unicode_lower, METH_NOARGS, lower__doc__}, - {"lstrip", (PyCFunction) unicode_lstrip, METH_VARARGS, lstrip__doc__}, + UNICODE_LJUST_METHODDEF + UNICODE_LOWER_METHODDEF + UNICODE_LSTRIP_METHODDEF {"rfind", (PyCFunction) unicode_rfind, METH_VARARGS, rfind__doc__}, {"rindex", (PyCFunction) unicode_rindex, METH_VARARGS, rindex__doc__}, - {"rjust", (PyCFunction) unicode_rjust, METH_VARARGS, rjust__doc__}, - {"rstrip", (PyCFunction) unicode_rstrip, METH_VARARGS, rstrip__doc__}, - {"rpartition", (PyCFunction) unicode_rpartition, METH_O, rpartition__doc__}, - {"splitlines", (PyCFunction) unicode_splitlines, - METH_VARARGS | METH_KEYWORDS, splitlines__doc__}, - {"strip", (PyCFunction) unicode_strip, METH_VARARGS, strip__doc__}, - {"swapcase", (PyCFunction) unicode_swapcase, METH_NOARGS, swapcase__doc__}, - {"translate", (PyCFunction) unicode_translate, METH_O, translate__doc__}, - {"upper", (PyCFunction) unicode_upper, METH_NOARGS, upper__doc__}, + UNICODE_RJUST_METHODDEF + UNICODE_RSTRIP_METHODDEF + UNICODE_RPARTITION_METHODDEF + UNICODE_SPLITLINES_METHODDEF + UNICODE_STRIP_METHODDEF + UNICODE_SWAPCASE_METHODDEF + UNICODE_TRANSLATE_METHODDEF + UNICODE_UPPER_METHODDEF {"startswith", (PyCFunction) unicode_startswith, METH_VARARGS, startswith__doc__}, {"endswith", (PyCFunction) unicode_endswith, METH_VARARGS, endswith__doc__}, - {"islower", (PyCFunction) unicode_islower, METH_NOARGS, islower__doc__}, - {"isupper", (PyCFunction) unicode_isupper, METH_NOARGS, isupper__doc__}, - {"istitle", (PyCFunction) unicode_istitle, METH_NOARGS, istitle__doc__}, - {"isspace", (PyCFunction) unicode_isspace, METH_NOARGS, isspace__doc__}, - {"isdecimal", (PyCFunction) unicode_isdecimal, METH_NOARGS, isdecimal__doc__}, - {"isdigit", (PyCFunction) unicode_isdigit, METH_NOARGS, isdigit__doc__}, - {"isnumeric", (PyCFunction) unicode_isnumeric, METH_NOARGS, isnumeric__doc__}, - {"isalpha", (PyCFunction) unicode_isalpha, METH_NOARGS, isalpha__doc__}, - {"isalnum", (PyCFunction) unicode_isalnum, METH_NOARGS, isalnum__doc__}, - {"isidentifier", (PyCFunction) unicode_isidentifier, METH_NOARGS, isidentifier__doc__}, - {"isprintable", (PyCFunction) unicode_isprintable, METH_NOARGS, isprintable__doc__}, - {"zfill", (PyCFunction) unicode_zfill, METH_VARARGS, zfill__doc__}, + UNICODE_ISLOWER_METHODDEF + UNICODE_ISUPPER_METHODDEF + UNICODE_ISTITLE_METHODDEF + UNICODE_ISSPACE_METHODDEF + UNICODE_ISDECIMAL_METHODDEF + UNICODE_ISDIGIT_METHODDEF + UNICODE_ISNUMERIC_METHODDEF + UNICODE_ISALPHA_METHODDEF + UNICODE_ISALNUM_METHODDEF + UNICODE_ISIDENTIFIER_METHODDEF + UNICODE_ISPRINTABLE_METHODDEF + UNICODE_ZFILL_METHODDEF {"format", (PyCFunction) do_string_format, METH_VARARGS | METH_KEYWORDS, format__doc__}, {"format_map", (PyCFunction) do_string_format_map, METH_O, format_map__doc__}, - {"__format__", (PyCFunction) unicode__format__, METH_VARARGS, p_format__doc__}, + UNICODE___FORMAT___METHODDEF UNICODE_MAKETRANS_METHODDEF - {"__sizeof__", (PyCFunction) unicode__sizeof__, METH_NOARGS, sizeof__doc__}, + UNICODE_SIZEOF_METHODDEF #if 0 /* These methods are just used for debugging the implementation. */ {"_decimal2ascii", (PyCFunction) unicode__decimal2ascii, METH_NOARGS}, -- cgit v1.2.1 From 6c812b4a4ef712e449e029dc7253e34c29ec3cff Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Mon, 16 Jan 2017 21:49:13 +0900 Subject: Issue #20180: forgot to update AC output. --- Objects/clinic/unicodeobject.c.h | 44 +++++++++++++++++++--------------------- Objects/unicodeobject.c | 36 ++++++++++++++++---------------- 2 files changed, 39 insertions(+), 41 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index 5873ce1972..610178dc27 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -6,9 +6,9 @@ PyDoc_STRVAR(unicode_title__doc__, "title($self, /)\n" "--\n" "\n" -"Return a version of the string where each word is capitalized.\n" +"Return a version of the string where each word is titlecased.\n" "\n" -"More specifically, words start with upper cased characters and all remaining\n" +"More specifically, words start with uppercased characters and all remaining\n" "cased characters have lower case."); #define UNICODE_TITLE_METHODDEF \ @@ -48,7 +48,7 @@ PyDoc_STRVAR(unicode_casefold__doc__, "casefold($self, /)\n" "--\n" "\n" -"Return a version of S suitable for caseless comparisons."); +"Return a version of the string suitable for caseless comparisons."); #define UNICODE_CASEFOLD_METHODDEF \ {"casefold", (PyCFunction)unicode_casefold, METH_NOARGS, unicode_casefold__doc__}, @@ -97,12 +97,12 @@ PyDoc_STRVAR(unicode_encode__doc__, "encode($self, /, encoding=\'utf-8\', errors=\'strict\')\n" "--\n" "\n" -"Encode a string using the codec registered for encoding.\n" +"Encode the string using the codec registered for encoding.\n" "\n" " encoding\n" " The encoding in which to encode the string.\n" " errors\n" -" The error handling scheme to use for the handling of encoding errors.\n" +" The error handling scheme to use for encoding errors.\n" " The default is \'strict\' meaning that encoding errors raise a\n" " UnicodeEncodeError. Other possible values are \'ignore\', \'replace\' and\n" " \'xmlcharrefreplace\' as well as any other name registered with\n" @@ -169,7 +169,7 @@ PyDoc_STRVAR(unicode_islower__doc__, "islower($self, /)\n" "--\n" "\n" -"Return whether the string is a lowercase string; False otherwise.\n" +"Return True if the string is a lowercase string, False otherwise.\n" "\n" "A string is lowercase if all cased characters in the string are lowercase and\n" "there is at least one cased character in the string."); @@ -190,7 +190,7 @@ PyDoc_STRVAR(unicode_isupper__doc__, "isupper($self, /)\n" "--\n" "\n" -"Return True if the string is an uppercase string; False otherwise.\n" +"Return True if the string is an uppercase string, False otherwise.\n" "\n" "A string is uppercase if all cased characters in the string are uppercase and\n" "there is at least one cased character in the string."); @@ -211,7 +211,7 @@ PyDoc_STRVAR(unicode_istitle__doc__, "istitle($self, /)\n" "--\n" "\n" -"Return True if the string is a title-cased string; False otherwise.\n" +"Return True if the string is a title-cased string, False otherwise.\n" "\n" "In a title-cased string, upper- and title-case characters may only\n" "follow uncased characters and lowercase characters only cased ones."); @@ -232,7 +232,7 @@ PyDoc_STRVAR(unicode_isspace__doc__, "isspace($self, /)\n" "--\n" "\n" -"Return True if the string is a whitespace string; False otherwise.\n" +"Return True if the string is a whitespace string, False otherwise.\n" "\n" "A string is whitespace if all characters in the string are whitespace and there\n" "is at least one character in the string."); @@ -253,7 +253,7 @@ PyDoc_STRVAR(unicode_isalpha__doc__, "isalpha($self, /)\n" "--\n" "\n" -"Return True if the string is an alphabetic string; False otherwise.\n" +"Return True if the string is an alphabetic string, False otherwise.\n" "\n" "A string is alphabetic if all characters in the string are alphabetic and there\n" "is at least one character in the string."); @@ -274,7 +274,7 @@ PyDoc_STRVAR(unicode_isalnum__doc__, "isalnum($self, /)\n" "--\n" "\n" -"Return True if the string is an alpha-numeric string; False otherwise.\n" +"Return True if the string is an alpha-numeric string, False otherwise.\n" "\n" "A string is alpha-numeric if all characters in the string are alpha-numeric and\n" "there is at least one character in the string."); @@ -295,9 +295,9 @@ PyDoc_STRVAR(unicode_isdecimal__doc__, "isdecimal($self, /)\n" "--\n" "\n" -"Return True if the string is a decimal string; False otherwise.\n" +"Return True if the string is a decimal string, False otherwise.\n" "\n" -"A string is a digit string if all characters in the string are decimal and\n" +"A string is a decimal string if all characters in the string are decimal and\n" "there is at least one character in the string."); #define UNICODE_ISDECIMAL_METHODDEF \ @@ -316,7 +316,7 @@ PyDoc_STRVAR(unicode_isdigit__doc__, "isdigit($self, /)\n" "--\n" "\n" -"Return True if the string is a digit string; False otherwise.\n" +"Return True if the string is a digit string, False otherwise.\n" "\n" "A string is a digit string if all characters in the string are digits and there\n" "is at least one character in the string."); @@ -337,7 +337,7 @@ PyDoc_STRVAR(unicode_isnumeric__doc__, "isnumeric($self, /)\n" "--\n" "\n" -"Return True if the string is an numeric string; False otherwise.\n" +"Return True if the string is a numeric string, False otherwise.\n" "\n" "A string is numeric if all characters in the string are numeric and there is at\n" "least one character in the string."); @@ -358,7 +358,7 @@ PyDoc_STRVAR(unicode_isidentifier__doc__, "isidentifier($self, /)\n" "--\n" "\n" -"Return True if the string is a valid Python identifier; False otherwise.\n" +"Return True if the string is a valid Python identifier, False otherwise.\n" "\n" "Use keyword.iskeyword() to test for reserved identifiers such as \"def\" and\n" "\"class\"."); @@ -379,7 +379,7 @@ PyDoc_STRVAR(unicode_isprintable__doc__, "isprintable($self, /)\n" "--\n" "\n" -"Return True if the string is printable; False otherwise.\n" +"Return True if the string is printable, False otherwise.\n" "\n" "A string is printable if all of its characters are considered printable in\n" "repr() or if it is empty."); @@ -402,9 +402,7 @@ PyDoc_STRVAR(unicode_join__doc__, "\n" "Concatenate any number of strings.\n" "\n" -"The string whose method is called is inserted in between each pair of given\n" -"strings.\n" -"\n" +"The string whose method is called is inserted in between each given strings.\n" "The result is returned as a new string.\n" "\n" "Example: \'.\'.join([\'ab\', \'pq\', \'rs\']) -> \'ab.pq.rs\'"); @@ -865,7 +863,7 @@ PyDoc_STRVAR(unicode_zfill__doc__, "\n" "Pad a numeric string with zeros on the left, to fill a field of the given width.\n" "\n" -"The original string is never truncated."); +"The string is never truncated."); #define UNICODE_ZFILL_METHODDEF \ {"zfill", (PyCFunction)unicode_zfill, METH_O, unicode_zfill__doc__}, @@ -892,7 +890,7 @@ PyDoc_STRVAR(unicode___format____doc__, "__format__($self, format_spec, /)\n" "--\n" "\n" -"Return a formatted version of S as described by format_spec."); +"Return a formatted version of the string as described by format_spec."); #define UNICODE___FORMAT___METHODDEF \ {"__format__", (PyCFunction)unicode___format__, METH_O, unicode___format____doc__}, @@ -932,4 +930,4 @@ unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) { return unicode_sizeof_impl(self); } -/*[clinic end generated code: output=11b54b7b810af538 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3b9b1e1f71ba3b00 input=a9049054013a1b77]*/ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index acf59e4d13..e2bdf088ab 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -49,7 +49,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #endif /*[clinic input] -class str "PyUnicodeObject *" "&PyUnicode_Type" +class str "PyObject *" "&PyUnicode_Type" [clinic start generated code]*/ /*[clinic end generated code: output=da39a3ee5e6b4b0d input=4884c934de622cf6]*/ @@ -10737,7 +10737,7 @@ cased characters have lower case. static PyObject * unicode_title_impl(PyObject *self) -/*[clinic end generated code: output=c75ae03809574902 input=4eb12c1bb8642cb9]*/ +/*[clinic end generated code: output=c75ae03809574902 input=fa945d669b26e683]*/ { if (PyUnicode_READY(self) == -1) return NULL; @@ -10772,7 +10772,7 @@ Return a version of the string suitable for caseless comparisons. static PyObject * unicode_casefold_impl(PyObject *self) -/*[clinic end generated code: output=0120daf657ca40af input=a96f2b0d3daabd94]*/ +/*[clinic end generated code: output=0120daf657ca40af input=384d66cc2ae30daf]*/ { if (PyUnicode_READY(self) == -1) return NULL; @@ -11510,7 +11510,7 @@ Encode the string using the codec registered for encoding. static PyObject * unicode_encode_impl(PyObject *self, const char *encoding, const char *errors) -/*[clinic end generated code: output=bf78b6e2a9470e3c input=12fcb2e5798e96dc]*/ +/*[clinic end generated code: output=bf78b6e2a9470e3c input=f0a9eb293d08fe02]*/ { return PyUnicode_AsEncodedString(self, encoding, errors); } @@ -11730,7 +11730,7 @@ there is at least one cased character in the string. static PyObject * unicode_islower_impl(PyObject *self) -/*[clinic end generated code: output=dbd41995bd005b81 input=46eeb20d935af050]*/ +/*[clinic end generated code: output=dbd41995bd005b81 input=acec65ac6821ae47]*/ { Py_ssize_t i, length; int kind; @@ -11775,7 +11775,7 @@ there is at least one cased character in the string. static PyObject * unicode_isupper_impl(PyObject *self) -/*[clinic end generated code: output=049209c8e7f15f59 input=dd0a595fc871eee0]*/ +/*[clinic end generated code: output=049209c8e7f15f59 input=e9b1feda5d17f2d3]*/ { Py_ssize_t i, length; int kind; @@ -11820,7 +11820,7 @@ follow uncased characters and lowercase characters only cased ones. static PyObject * unicode_istitle_impl(PyObject *self) -/*[clinic end generated code: output=e9bf6eb91f5d3f0e input=2c56883d113d644d]*/ +/*[clinic end generated code: output=e9bf6eb91f5d3f0e input=98d32bd2e1f06f8c]*/ { Py_ssize_t i, length; int kind; @@ -11878,7 +11878,7 @@ is at least one character in the string. static PyObject * unicode_isspace_impl(PyObject *self) -/*[clinic end generated code: output=163a63bfa08ac2b9 input=b9506a23e312d203]*/ +/*[clinic end generated code: output=163a63bfa08ac2b9 input=fe462cb74f8437d8]*/ { Py_ssize_t i, length; int kind; @@ -11918,7 +11918,7 @@ is at least one character in the string. static PyObject * unicode_isalpha_impl(PyObject *self) -/*[clinic end generated code: output=cc81b9ac3883ec4f input=17e3788814472079]*/ +/*[clinic end generated code: output=cc81b9ac3883ec4f input=d0fd18a96cbca5eb]*/ { Py_ssize_t i, length; int kind; @@ -11957,7 +11957,7 @@ there is at least one character in the string. static PyObject * unicode_isalnum_impl(PyObject *self) -/*[clinic end generated code: output=a5a23490ffc3660c input=d350c4f7c59b4758]*/ +/*[clinic end generated code: output=a5a23490ffc3660c input=5c6579bf2e04758c]*/ { int kind; void *data; @@ -11999,7 +11999,7 @@ there is at least one character in the string. static PyObject * unicode_isdecimal_impl(PyObject *self) -/*[clinic end generated code: output=fb2dcdb62d3fc548 input=40536fb80e5f1dc1]*/ +/*[clinic end generated code: output=fb2dcdb62d3fc548 input=336bc97ab4c8268f]*/ { Py_ssize_t i, length; int kind; @@ -12038,7 +12038,7 @@ is at least one character in the string. static PyObject * unicode_isdigit_impl(PyObject *self) -/*[clinic end generated code: output=10a6985311da6858 input=c6a222be1aaec2af]*/ +/*[clinic end generated code: output=10a6985311da6858 input=901116c31deeea4c]*/ { Py_ssize_t i, length; int kind; @@ -12078,7 +12078,7 @@ least one character in the string. static PyObject * unicode_isnumeric_impl(PyObject *self) -/*[clinic end generated code: output=9172a32d9013051a input=e3b37b2cc8854f35]*/ +/*[clinic end generated code: output=9172a32d9013051a input=722507db976f826c]*/ { Py_ssize_t i, length; int kind; @@ -12154,7 +12154,7 @@ Use keyword.iskeyword() to test for reserved identifiers such as "def" and static PyObject * unicode_isidentifier_impl(PyObject *self) -/*[clinic end generated code: output=fe585a9666572905 input=95eebe40d6d91234]*/ +/*[clinic end generated code: output=fe585a9666572905 input=916b0a3c9f57e919]*/ { return PyBool_FromLong(PyUnicode_IsIdentifier(self)); } @@ -12170,7 +12170,7 @@ repr() or if it is empty. static PyObject * unicode_isprintable_impl(PyObject *self) -/*[clinic end generated code: output=3ab9626cd32dd1a0 input=20c53134171af84e]*/ +/*[clinic end generated code: output=3ab9626cd32dd1a0 input=98a0e1c2c1813209]*/ { Py_ssize_t i, length; int kind; @@ -12211,7 +12211,7 @@ Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs' static PyObject * unicode_join(PyObject *self, PyObject *iterable) -/*[clinic end generated code: output=6857e7cecfe7bf98 input=465f62626109db6b]*/ +/*[clinic end generated code: output=6857e7cecfe7bf98 input=d8311e5ccbafbeb6]*/ { return PyUnicode_Join(self, iterable); } @@ -13309,7 +13309,7 @@ The string is never truncated. static PyObject * unicode_zfill_impl(PyObject *self, Py_ssize_t width) -/*[clinic end generated code: output=e13fb6bdf8e3b9df input=3559257ab7bfed6e]*/ +/*[clinic end generated code: output=e13fb6bdf8e3b9df input=c6b2f772c6f27799]*/ { Py_ssize_t fill; PyObject *u; @@ -13814,7 +13814,7 @@ Return a formatted version of the string as described by format_spec. static PyObject * unicode___format___impl(PyObject *self, PyObject *format_spec) -/*[clinic end generated code: output=45fceaca6d2ba4c8 input=1f0623ca7b7c5981]*/ +/*[clinic end generated code: output=45fceaca6d2ba4c8 input=5e135645d167a214]*/ { _PyUnicodeWriter writer; int ret; -- cgit v1.2.1 From 7542c621d4273f5ea075c1127e5dbdb33ff6677f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 16 Jan 2017 17:18:53 +0100 Subject: Optimize _PyCFunction_FastCallKeywords() Issue #29259: Write fast path in _PyCFunction_FastCallKeywords() for METH_FASTCALL, avoid the creation of a temporary dictionary for keyword arguments. Cleanup also _PyCFunction_FastCallDict(): * Don't dereference func before checking that it's not NULL * Move code to raise the "no keyword argument" exception into a new no_keyword_error label. Update python-gdb.py for the change. --- Objects/methodobject.c | 167 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 131 insertions(+), 36 deletions(-) (limited to 'Objects') diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 14750b6318..1e9ad0df91 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -89,7 +89,7 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) assert(kwds == NULL || PyDict_Check(kwds)); /* PyCFunction_Call() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the + because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!PyErr_Occurred()); @@ -155,14 +155,14 @@ PyObject * _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { - PyCFunctionObject *func = (PyCFunctionObject*)func_obj; - PyCFunction meth = PyCFunction_GET_FUNCTION(func); - PyObject *self = PyCFunction_GET_SELF(func); + PyCFunctionObject *func; + PyCFunction meth; + PyObject *self; PyObject *result; int flags; - assert(PyCFunction_Check(func)); - assert(func != NULL); + assert(func_obj != NULL); + assert(PyCFunction_Check(func_obj)); assert(nargs >= 0); assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); @@ -172,34 +172,28 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, caller loses its exception */ assert(!PyErr_Occurred()); + func = (PyCFunctionObject*)func_obj; + meth = PyCFunction_GET_FUNCTION(func); + self = PyCFunction_GET_SELF(func); flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); switch (flags) { case METH_NOARGS: + if (nargs != 0) { + goto no_keyword_error; + } + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", func->m_ml->ml_name); return NULL; } - if (nargs != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", - func->m_ml->ml_name, nargs); - return NULL; - } - result = (*meth) (self, NULL); break; case METH_O: - if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { - PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - func->m_ml->ml_name); - return NULL; - } - if (nargs != 1) { PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", @@ -207,20 +201,22 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, return NULL; } + if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; + } + result = (*meth) (self, args[0]); break; case METH_VARARGS: case METH_VARARGS | METH_KEYWORDS: { - /* Slow-path: create a temporary tuple */ + /* Slow-path: create a temporary tuple for positional arguments */ PyObject *tuple; - if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no keyword arguments", - func->m_ml->ml_name); - return NULL; + if (!(flags & METH_KEYWORDS) + && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { + goto no_keyword_error; } tuple = _PyStack_AsTuple(args, nargs); @@ -267,35 +263,134 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, result = _Py_CheckFunctionResult(func_obj, result, NULL); return result; + +no_keyword_error: + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + func->m_ml->ml_name, nargs); + return NULL; } PyObject * -_PyCFunction_FastCallKeywords(PyObject *func, PyObject **stack, +_PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { - PyObject *kwdict, *result; + PyCFunctionObject *func; + PyCFunction meth; + PyObject *self, *result; Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); + int flags; - assert(PyCFunction_Check(func)); + assert(func_obj != NULL); + assert(PyCFunction_Check(func_obj)); assert(nargs >= 0); assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - assert((nargs == 0 && nkwargs == 0) || stack != NULL); + assert((nargs == 0 && nkwargs == 0) || args != NULL); /* kwnames must only contains str strings, no subclass, and all keys must be unique */ - if (nkwargs > 0) { - kwdict = _PyStack_AsDict(stack + nargs, kwnames); - if (kwdict == NULL) { + /* _PyCFunction_FastCallKeywords() must not be called with an exception + set, because it can clear it (directly or indirectly) and so the caller + loses its exception */ + assert(!PyErr_Occurred()); + + func = (PyCFunctionObject*)func_obj; + meth = PyCFunction_GET_FUNCTION(func); + self = PyCFunction_GET_SELF(func); + flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + + switch (flags) + { + case METH_NOARGS: + if (nargs != 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + func->m_ml->ml_name, nargs); + return NULL; + } + + if (nkwargs) { + goto no_keyword_error; + } + + result = (*meth) (self, NULL); + break; + + case METH_O: + if (nargs != 1) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes exactly one argument (%zd given)", + func->m_ml->ml_name, nargs); return NULL; } + + if (nkwargs) { + goto no_keyword_error; + } + + result = (*meth) (self, args[0]); + break; + + case METH_FASTCALL: + /* Fast-path: avoid temporary dict to pass keyword arguments */ + result = ((_PyCFunctionFast)meth) (self, args, nargs, kwnames); + break; + + case METH_VARARGS: + case METH_VARARGS | METH_KEYWORDS: + { + /* Slow-path: create a temporary tuple for positional arguments + and a temporary dict for keyword arguments */ + PyObject *argtuple; + + if (!(flags & METH_KEYWORDS) && nkwargs) { + goto no_keyword_error; + } + + argtuple = _PyStack_AsTuple(args, nargs); + if (argtuple == NULL) { + return NULL; + } + + if (flags & METH_KEYWORDS) { + PyObject *kwdict; + + if (nkwargs > 0) { + kwdict = _PyStack_AsDict(args + nargs, kwnames); + if (kwdict == NULL) { + Py_DECREF(argtuple); + return NULL; + } + } + else { + kwdict = NULL; + } + + result = (*(PyCFunctionWithKeywords)meth) (self, argtuple, kwdict); + Py_XDECREF(kwdict); + } + else { + result = (*meth) (self, argtuple); + } + Py_DECREF(argtuple); + break; } - else { - kwdict = NULL; + + default: + PyErr_SetString(PyExc_SystemError, + "Bad call flags in _PyCFunction_FastCallKeywords. " + "METH_OLDARGS is no longer supported!"); + return NULL; } - result = _PyCFunction_FastCallDict(func, stack, nargs, kwdict); - Py_XDECREF(kwdict); + result = _Py_CheckFunctionResult(func_obj, result, NULL); return result; + +no_keyword_error: + PyErr_Format(PyExc_TypeError, + "%.200s() takes no keyword arguments", + func->m_ml->ml_name); + return NULL; } /* Methods (the standard built-in methods, that is) */ -- cgit v1.2.1 From 7e1c513a9ea54b50e4c3b947208d1306aba5362f Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 16 Jan 2017 23:50:53 +0100 Subject: Add _PyStack_AsTupleSlice() helper --- Objects/abstract.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 5726160c08..bba946e8ef 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2274,7 +2274,30 @@ _PyStack_AsTuple(PyObject **stack, Py_ssize_t nargs) Py_INCREF(item); PyTuple_SET_ITEM(args, i, item); } + return args; +} + +PyObject* +_PyStack_AsTupleSlice(PyObject **stack, Py_ssize_t nargs, + Py_ssize_t start, Py_ssize_t end) +{ + PyObject *args; + Py_ssize_t i; + + assert(0 <= start); + assert(end <= nargs); + assert(start <= end); + args = PyTuple_New(end - start); + if (args == NULL) { + return NULL; + } + + for (i=start; i < end; i++) { + PyObject *item = stack[i]; + Py_INCREF(item); + PyTuple_SET_ITEM(args, i - start, item); + } return args; } -- cgit v1.2.1 From 55d565ff6a595485dcb3065529ada04c84e5505e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 16 Jan 2017 23:52:00 +0100 Subject: type_prepare() now uses fast call (METH_FASTCALL) --- Objects/typeobject.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'Objects') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 05fc7b88d3..a521177210 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3112,7 +3112,8 @@ type_subclasses(PyTypeObject *type, PyObject *args_ignored) } static PyObject * -type_prepare(PyObject *self, PyObject *args, PyObject *kwds) +type_prepare(PyObject *self, PyObject **args, Py_ssize_t nargs, + PyObject *kwnames) { return PyDict_New(); } @@ -3216,7 +3217,7 @@ static PyMethodDef type_methods[] = { {"__subclasses__", (PyCFunction)type_subclasses, METH_NOARGS, PyDoc_STR("__subclasses__() -> list of immediate subclasses")}, {"__prepare__", (PyCFunction)type_prepare, - METH_VARARGS | METH_KEYWORDS | METH_CLASS, + METH_FASTCALL | METH_CLASS, PyDoc_STR("__prepare__() -> dict\n" "used to create the namespace for the class statement")}, {"__instancecheck__", type___instancecheck__, METH_O, -- cgit v1.2.1 From 271403abe36069797ac332e1c6eae3473878db20 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 17 Jan 2017 01:29:01 +0100 Subject: Rename _PyArg_ParseStack to _PyArg_ParseStackAndKeywords Issue #29286. --- Objects/abstract.c | 2 +- Objects/clinic/bytearrayobject.c.h | 10 +++++----- Objects/clinic/bytesobject.c.h | 10 +++++----- Objects/clinic/unicodeobject.c.h | 10 +++++----- 4 files changed, 16 insertions(+), 16 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index bba946e8ef..48fdf6541a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2485,7 +2485,7 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg /* kwnames must only contains str strings, no subclass, and all keys must be unique: these checks are implemented in Python/ceval.c and - _PyArg_ParseStack(). */ + _PyArg_ParseStackAndKeywords(). */ if (PyFunction_Check(callable)) { return _PyFunction_FastCallKeywords(callable, stack, nargs, kwnames); diff --git a/Objects/clinic/bytearrayobject.c.h b/Objects/clinic/bytearrayobject.c.h index c75acb75cf..4ab4329727 100644 --- a/Objects/clinic/bytearrayobject.c.h +++ b/Objects/clinic/bytearrayobject.c.h @@ -66,7 +66,7 @@ bytearray_translate(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *table; PyObject *deletechars = NULL; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &table, &deletechars)) { goto exit; } @@ -196,7 +196,7 @@ bytearray_split(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyOb PyObject *sep = Py_None; Py_ssize_t maxsplit = -1; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &sep, &maxsplit)) { goto exit; } @@ -270,7 +270,7 @@ bytearray_rsplit(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyO PyObject *sep = Py_None; Py_ssize_t maxsplit = -1; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &sep, &maxsplit)) { goto exit; } @@ -562,7 +562,7 @@ bytearray_decode(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyO const char *encoding = NULL; const char *errors = NULL; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &encoding, &errors)) { goto exit; } @@ -608,7 +608,7 @@ bytearray_splitlines(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, static _PyArg_Parser _parser = {"|i:splitlines", _keywords, 0}; int keepends = 0; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &keepends)) { goto exit; } diff --git a/Objects/clinic/bytesobject.c.h b/Objects/clinic/bytesobject.c.h index a11ebd2774..dd1ec918bd 100644 --- a/Objects/clinic/bytesobject.c.h +++ b/Objects/clinic/bytesobject.c.h @@ -31,7 +31,7 @@ bytes_split(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kw PyObject *sep = Py_None; Py_ssize_t maxsplit = -1; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &sep, &maxsplit)) { goto exit; } @@ -150,7 +150,7 @@ bytes_rsplit(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *k PyObject *sep = Py_None; Py_ssize_t maxsplit = -1; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &sep, &maxsplit)) { goto exit; } @@ -296,7 +296,7 @@ bytes_translate(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject PyObject *table; PyObject *deletechars = NULL; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &table, &deletechars)) { goto exit; } @@ -427,7 +427,7 @@ bytes_decode(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *k const char *encoding = NULL; const char *errors = NULL; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &encoding, &errors)) { goto exit; } @@ -460,7 +460,7 @@ bytes_splitlines(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObjec static _PyArg_Parser _parser = {"|i:splitlines", _keywords, 0}; int keepends = 0; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &keepends)) { goto exit; } diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index 610178dc27..b2d91b7aaa 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -123,7 +123,7 @@ unicode_encode(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwna const char *encoding = NULL; const char *errors = NULL; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &encoding, &errors)) { goto exit; } @@ -155,7 +155,7 @@ unicode_expandtabs(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject * static _PyArg_Parser _parser = {"|i:expandtabs", _keywords, 0}; int tabsize = 8; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &tabsize)) { goto exit; } @@ -650,7 +650,7 @@ unicode_split(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnam PyObject *sep = Py_None; Py_ssize_t maxsplit = -1; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &sep, &maxsplit)) { goto exit; } @@ -723,7 +723,7 @@ unicode_rsplit(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwna PyObject *sep = Py_None; Py_ssize_t maxsplit = -1; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &sep, &maxsplit)) { goto exit; } @@ -756,7 +756,7 @@ unicode_splitlines(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject * static _PyArg_Parser _parser = {"|i:splitlines", _keywords, 0}; int keepends = 0; - if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, &keepends)) { goto exit; } -- cgit v1.2.1 From 36b536afbf9f8adfc6511521bb8596ad7762a247 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 17 Jan 2017 01:57:29 +0100 Subject: _PyStack_UnpackDict() now returns -1 on error Issue #29286. Change _PyStack_UnpackDict() prototype to be able to notify of failure when args is NULL. --- Objects/abstract.c | 16 +++++++++------- Objects/methodobject.c | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 48fdf6541a..ee50f02057 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2421,9 +2421,9 @@ _PyStack_AsDict(PyObject **values, PyObject *kwnames) return kwdict; } -PyObject ** +int _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, - PyObject **p_kwnames, PyObject *func) + PyObject ***p_stack, PyObject **p_kwnames, PyObject *func) { PyObject **stack, **kwstack; Py_ssize_t nkwargs; @@ -2435,25 +2435,26 @@ _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, assert(kwargs == NULL || PyDict_CheckExact(kwargs)); if (kwargs == NULL || (nkwargs = PyDict_GET_SIZE(kwargs)) == 0) { + *p_stack = args; *p_kwnames = NULL; - return args; + return 0; } if ((size_t)nargs > PY_SSIZE_T_MAX / sizeof(stack[0]) - (size_t)nkwargs) { PyErr_NoMemory(); - return NULL; + return -1; } stack = PyMem_Malloc((nargs + nkwargs) * sizeof(stack[0])); if (stack == NULL) { PyErr_NoMemory(); - return NULL; + return -1; } kwnames = PyTuple_New(nkwargs); if (kwnames == NULL) { PyMem_Free(stack); - return NULL; + return -1; } /* Copy position arguments (borrowed references) */ @@ -2472,8 +2473,9 @@ _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, i++; } + *p_stack = stack; *p_kwnames = kwnames; - return stack; + return 0; } PyObject * diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 1e9ad0df91..7bff6a037b 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -240,8 +240,8 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, PyObject *kwnames; _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; - stack = _PyStack_UnpackDict(args, nargs, kwargs, &kwnames, func_obj); - if (stack == NULL) { + if (_PyStack_UnpackDict(args, nargs, kwargs, + &stack, &kwnames, func_obj) < 0) { return NULL; } -- cgit v1.2.1 From 7372e18fa83aa35766f8f6fdf3aed27fac2d52d2 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 17 Jan 2017 01:35:17 +0100 Subject: Run Argument Clinic: METH_VARARGS=>METH_FASTCALL Issue #29286. Run Argument Clinic to get the new faster METH_FASTCALL calling convention for functions using only positional arguments. --- Objects/clinic/bytearrayobject.c.h | 52 ++++++++++++++++++++++++++------------ Objects/clinic/bytesobject.c.h | 22 +++++++++++----- Objects/clinic/unicodeobject.c.h | 52 ++++++++++++++++++++++++++------------ 3 files changed, 87 insertions(+), 39 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/bytearrayobject.c.h b/Objects/clinic/bytearrayobject.c.h index 4ab4329727..3e39e9a7bd 100644 --- a/Objects/clinic/bytearrayobject.c.h +++ b/Objects/clinic/bytearrayobject.c.h @@ -88,22 +88,26 @@ PyDoc_STRVAR(bytearray_maketrans__doc__, "The bytes objects frm and to must be of the same length."); #define BYTEARRAY_MAKETRANS_METHODDEF \ - {"maketrans", (PyCFunction)bytearray_maketrans, METH_VARARGS|METH_STATIC, bytearray_maketrans__doc__}, + {"maketrans", (PyCFunction)bytearray_maketrans, METH_FASTCALL|METH_STATIC, bytearray_maketrans__doc__}, static PyObject * bytearray_maketrans_impl(Py_buffer *frm, Py_buffer *to); static PyObject * -bytearray_maketrans(void *null, PyObject *args) +bytearray_maketrans(void *null, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; Py_buffer frm = {NULL, NULL}; Py_buffer to = {NULL, NULL}; - if (!PyArg_ParseTuple(args, "y*y*:maketrans", + if (!_PyArg_ParseStack(args, nargs, "y*y*:maketrans", &frm, &to)) { goto exit; } + + if (!_PyArg_NoStackKeywords("maketrans", kwnames)) { + goto exit; + } return_value = bytearray_maketrans_impl(&frm, &to); exit: @@ -133,24 +137,28 @@ PyDoc_STRVAR(bytearray_replace__doc__, "replaced."); #define BYTEARRAY_REPLACE_METHODDEF \ - {"replace", (PyCFunction)bytearray_replace, METH_VARARGS, bytearray_replace__doc__}, + {"replace", (PyCFunction)bytearray_replace, METH_FASTCALL, bytearray_replace__doc__}, static PyObject * bytearray_replace_impl(PyByteArrayObject *self, Py_buffer *old, Py_buffer *new, Py_ssize_t count); static PyObject * -bytearray_replace(PyByteArrayObject *self, PyObject *args) +bytearray_replace(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; Py_buffer old = {NULL, NULL}; Py_buffer new = {NULL, NULL}; Py_ssize_t count = -1; - if (!PyArg_ParseTuple(args, "y*y*|n:replace", + if (!_PyArg_ParseStack(args, nargs, "y*y*|n:replace", &old, &new, &count)) { goto exit; } + + if (!_PyArg_NoStackKeywords("replace", kwnames)) { + goto exit; + } return_value = bytearray_replace_impl(self, &old, &new, count); exit: @@ -310,22 +318,26 @@ PyDoc_STRVAR(bytearray_insert__doc__, " The item to be inserted."); #define BYTEARRAY_INSERT_METHODDEF \ - {"insert", (PyCFunction)bytearray_insert, METH_VARARGS, bytearray_insert__doc__}, + {"insert", (PyCFunction)bytearray_insert, METH_FASTCALL, bytearray_insert__doc__}, static PyObject * bytearray_insert_impl(PyByteArrayObject *self, Py_ssize_t index, int item); static PyObject * -bytearray_insert(PyByteArrayObject *self, PyObject *args) +bytearray_insert(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; Py_ssize_t index; int item; - if (!PyArg_ParseTuple(args, "nO&:insert", + if (!_PyArg_ParseStack(args, nargs, "nO&:insert", &index, _getbytevalue, &item)) { goto exit; } + + if (!_PyArg_NoStackKeywords("insert", kwnames)) { + goto exit; + } return_value = bytearray_insert_impl(self, index, item); exit: @@ -387,21 +399,25 @@ PyDoc_STRVAR(bytearray_pop__doc__, "If no index argument is given, will pop the last item."); #define BYTEARRAY_POP_METHODDEF \ - {"pop", (PyCFunction)bytearray_pop, METH_VARARGS, bytearray_pop__doc__}, + {"pop", (PyCFunction)bytearray_pop, METH_FASTCALL, bytearray_pop__doc__}, static PyObject * bytearray_pop_impl(PyByteArrayObject *self, Py_ssize_t index); static PyObject * -bytearray_pop(PyByteArrayObject *self, PyObject *args) +bytearray_pop(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; Py_ssize_t index = -1; - if (!PyArg_ParseTuple(args, "|n:pop", + if (!_PyArg_ParseStack(args, nargs, "|n:pop", &index)) { goto exit; } + + if (!_PyArg_NoStackKeywords("pop", kwnames)) { + goto exit; + } return_value = bytearray_pop_impl(self, index); exit: @@ -673,21 +689,25 @@ PyDoc_STRVAR(bytearray_reduce_ex__doc__, "Return state information for pickling."); #define BYTEARRAY_REDUCE_EX_METHODDEF \ - {"__reduce_ex__", (PyCFunction)bytearray_reduce_ex, METH_VARARGS, bytearray_reduce_ex__doc__}, + {"__reduce_ex__", (PyCFunction)bytearray_reduce_ex, METH_FASTCALL, bytearray_reduce_ex__doc__}, static PyObject * bytearray_reduce_ex_impl(PyByteArrayObject *self, int proto); static PyObject * -bytearray_reduce_ex(PyByteArrayObject *self, PyObject *args) +bytearray_reduce_ex(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; int proto = 0; - if (!PyArg_ParseTuple(args, "|i:__reduce_ex__", + if (!_PyArg_ParseStack(args, nargs, "|i:__reduce_ex__", &proto)) { goto exit; } + + if (!_PyArg_NoStackKeywords("__reduce_ex__", kwnames)) { + goto exit; + } return_value = bytearray_reduce_ex_impl(self, proto); exit: @@ -711,4 +731,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) { return bytearray_sizeof_impl(self); } -/*[clinic end generated code: output=225342a680391b9c input=a9049054013a1b77]*/ +/*[clinic end generated code: output=e6c057d1cd7c2496 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/bytesobject.c.h b/Objects/clinic/bytesobject.c.h index dd1ec918bd..330cb84853 100644 --- a/Objects/clinic/bytesobject.c.h +++ b/Objects/clinic/bytesobject.c.h @@ -318,22 +318,26 @@ PyDoc_STRVAR(bytes_maketrans__doc__, "The bytes objects frm and to must be of the same length."); #define BYTES_MAKETRANS_METHODDEF \ - {"maketrans", (PyCFunction)bytes_maketrans, METH_VARARGS|METH_STATIC, bytes_maketrans__doc__}, + {"maketrans", (PyCFunction)bytes_maketrans, METH_FASTCALL|METH_STATIC, bytes_maketrans__doc__}, static PyObject * bytes_maketrans_impl(Py_buffer *frm, Py_buffer *to); static PyObject * -bytes_maketrans(void *null, PyObject *args) +bytes_maketrans(void *null, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; Py_buffer frm = {NULL, NULL}; Py_buffer to = {NULL, NULL}; - if (!PyArg_ParseTuple(args, "y*y*:maketrans", + if (!_PyArg_ParseStack(args, nargs, "y*y*:maketrans", &frm, &to)) { goto exit; } + + if (!_PyArg_NoStackKeywords("maketrans", kwnames)) { + goto exit; + } return_value = bytes_maketrans_impl(&frm, &to); exit: @@ -363,24 +367,28 @@ PyDoc_STRVAR(bytes_replace__doc__, "replaced."); #define BYTES_REPLACE_METHODDEF \ - {"replace", (PyCFunction)bytes_replace, METH_VARARGS, bytes_replace__doc__}, + {"replace", (PyCFunction)bytes_replace, METH_FASTCALL, bytes_replace__doc__}, static PyObject * bytes_replace_impl(PyBytesObject *self, Py_buffer *old, Py_buffer *new, Py_ssize_t count); static PyObject * -bytes_replace(PyBytesObject *self, PyObject *args) +bytes_replace(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; Py_buffer old = {NULL, NULL}; Py_buffer new = {NULL, NULL}; Py_ssize_t count = -1; - if (!PyArg_ParseTuple(args, "y*y*|n:replace", + if (!_PyArg_ParseStack(args, nargs, "y*y*|n:replace", &old, &new, &count)) { goto exit; } + + if (!_PyArg_NoStackKeywords("replace", kwnames)) { + goto exit; + } return_value = bytes_replace_impl(self, &old, &new, count); exit: @@ -499,4 +507,4 @@ bytes_fromhex(PyTypeObject *type, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=2dc3c93cfd2dc440 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2b8d3cff7e11045e input=a9049054013a1b77]*/ diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index b2d91b7aaa..d968cbe346 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -71,22 +71,26 @@ PyDoc_STRVAR(unicode_center__doc__, "Padding is done using the specified fill character (default is a space)."); #define UNICODE_CENTER_METHODDEF \ - {"center", (PyCFunction)unicode_center, METH_VARARGS, unicode_center__doc__}, + {"center", (PyCFunction)unicode_center, METH_FASTCALL, unicode_center__doc__}, static PyObject * unicode_center_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar); static PyObject * -unicode_center(PyObject *self, PyObject *args) +unicode_center(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; Py_ssize_t width; Py_UCS4 fillchar = ' '; - if (!PyArg_ParseTuple(args, "n|O&:center", + if (!_PyArg_ParseStack(args, nargs, "n|O&:center", &width, convert_uc, &fillchar)) { goto exit; } + + if (!_PyArg_NoStackKeywords("center", kwnames)) { + goto exit; + } return_value = unicode_center_impl(self, width, fillchar); exit: @@ -419,22 +423,26 @@ PyDoc_STRVAR(unicode_ljust__doc__, "Padding is done using the specified fill character (default is a space)."); #define UNICODE_LJUST_METHODDEF \ - {"ljust", (PyCFunction)unicode_ljust, METH_VARARGS, unicode_ljust__doc__}, + {"ljust", (PyCFunction)unicode_ljust, METH_FASTCALL, unicode_ljust__doc__}, static PyObject * unicode_ljust_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar); static PyObject * -unicode_ljust(PyObject *self, PyObject *args) +unicode_ljust(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; Py_ssize_t width; Py_UCS4 fillchar = ' '; - if (!PyArg_ParseTuple(args, "n|O&:ljust", + if (!_PyArg_ParseStack(args, nargs, "n|O&:ljust", &width, convert_uc, &fillchar)) { goto exit; } + + if (!_PyArg_NoStackKeywords("ljust", kwnames)) { + goto exit; + } return_value = unicode_ljust_impl(self, width, fillchar); exit: @@ -566,24 +574,28 @@ PyDoc_STRVAR(unicode_replace__doc__, "replaced."); #define UNICODE_REPLACE_METHODDEF \ - {"replace", (PyCFunction)unicode_replace, METH_VARARGS, unicode_replace__doc__}, + {"replace", (PyCFunction)unicode_replace, METH_FASTCALL, unicode_replace__doc__}, static PyObject * unicode_replace_impl(PyObject *self, PyObject *old, PyObject *new, Py_ssize_t count); static PyObject * -unicode_replace(PyObject *self, PyObject *args) +unicode_replace(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *old; PyObject *new; Py_ssize_t count = -1; - if (!PyArg_ParseTuple(args, "UU|n:replace", + if (!_PyArg_ParseStack(args, nargs, "UU|n:replace", &old, &new, &count)) { goto exit; } + + if (!_PyArg_NoStackKeywords("replace", kwnames)) { + goto exit; + } return_value = unicode_replace_impl(self, old, new, count); exit: @@ -599,22 +611,26 @@ PyDoc_STRVAR(unicode_rjust__doc__, "Padding is done using the specified fill character (default is a space)."); #define UNICODE_RJUST_METHODDEF \ - {"rjust", (PyCFunction)unicode_rjust, METH_VARARGS, unicode_rjust__doc__}, + {"rjust", (PyCFunction)unicode_rjust, METH_FASTCALL, unicode_rjust__doc__}, static PyObject * unicode_rjust_impl(PyObject *self, Py_ssize_t width, Py_UCS4 fillchar); static PyObject * -unicode_rjust(PyObject *self, PyObject *args) +unicode_rjust(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; Py_ssize_t width; Py_UCS4 fillchar = ' '; - if (!PyArg_ParseTuple(args, "n|O&:rjust", + if (!_PyArg_ParseStack(args, nargs, "n|O&:rjust", &width, convert_uc, &fillchar)) { goto exit; } + + if (!_PyArg_NoStackKeywords("rjust", kwnames)) { + goto exit; + } return_value = unicode_rjust_impl(self, width, fillchar); exit: @@ -799,23 +815,27 @@ PyDoc_STRVAR(unicode_maketrans__doc__, "must be a string, whose characters will be mapped to None in the result."); #define UNICODE_MAKETRANS_METHODDEF \ - {"maketrans", (PyCFunction)unicode_maketrans, METH_VARARGS|METH_STATIC, unicode_maketrans__doc__}, + {"maketrans", (PyCFunction)unicode_maketrans, METH_FASTCALL|METH_STATIC, unicode_maketrans__doc__}, static PyObject * unicode_maketrans_impl(PyObject *x, PyObject *y, PyObject *z); static PyObject * -unicode_maketrans(void *null, PyObject *args) +unicode_maketrans(void *null, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *x; PyObject *y = NULL; PyObject *z = NULL; - if (!PyArg_ParseTuple(args, "O|UU:maketrans", + if (!_PyArg_ParseStack(args, nargs, "O|UU:maketrans", &x, &y, &z)) { goto exit; } + + if (!_PyArg_NoStackKeywords("maketrans", kwnames)) { + goto exit; + } return_value = unicode_maketrans_impl(x, y, z); exit: @@ -930,4 +950,4 @@ unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) { return unicode_sizeof_impl(self); } -/*[clinic end generated code: output=3b9b1e1f71ba3b00 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=eb6a3ae361a1a379 input=a9049054013a1b77]*/ -- cgit v1.2.1 From 104cb4a3bacdf9764f9f8670a80da16390231337 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 17 Jan 2017 02:21:47 +0100 Subject: Run Argument Clinic: METH_VARARGS=>METH_FASTCALL Issue #29286. Run Argument Clinic to get the new faster METH_FASTCALL calling convention for functions using "boring" positional arguments. Manually fix _elementtree: _elementtree_XMLParser_doctype() must remain consistent with the clinic code. --- Objects/clinic/bytearrayobject.c.h | 32 ++++++++++++++++++++++---------- Objects/clinic/bytesobject.c.h | 32 ++++++++++++++++++++++---------- Objects/clinic/dictobject.c.h | 12 ++++++++---- Objects/clinic/unicodeobject.c.h | 34 +++++++++++++++++++++++----------- Objects/unicodeobject.c | 4 ++-- 5 files changed, 77 insertions(+), 37 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/bytearrayobject.c.h b/Objects/clinic/bytearrayobject.c.h index 3e39e9a7bd..a181d9a99b 100644 --- a/Objects/clinic/bytearrayobject.c.h +++ b/Objects/clinic/bytearrayobject.c.h @@ -463,22 +463,26 @@ PyDoc_STRVAR(bytearray_strip__doc__, "If the argument is omitted or None, strip leading and trailing ASCII whitespace."); #define BYTEARRAY_STRIP_METHODDEF \ - {"strip", (PyCFunction)bytearray_strip, METH_VARARGS, bytearray_strip__doc__}, + {"strip", (PyCFunction)bytearray_strip, METH_FASTCALL, bytearray_strip__doc__}, static PyObject * bytearray_strip_impl(PyByteArrayObject *self, PyObject *bytes); static PyObject * -bytearray_strip(PyByteArrayObject *self, PyObject *args) +bytearray_strip(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *bytes = Py_None; - if (!PyArg_UnpackTuple(args, "strip", + if (!_PyArg_UnpackStack(args, nargs, "strip", 0, 1, &bytes)) { goto exit; } + + if (!_PyArg_NoStackKeywords("strip", kwnames)) { + goto exit; + } return_value = bytearray_strip_impl(self, bytes); exit: @@ -494,22 +498,26 @@ PyDoc_STRVAR(bytearray_lstrip__doc__, "If the argument is omitted or None, strip leading ASCII whitespace."); #define BYTEARRAY_LSTRIP_METHODDEF \ - {"lstrip", (PyCFunction)bytearray_lstrip, METH_VARARGS, bytearray_lstrip__doc__}, + {"lstrip", (PyCFunction)bytearray_lstrip, METH_FASTCALL, bytearray_lstrip__doc__}, static PyObject * bytearray_lstrip_impl(PyByteArrayObject *self, PyObject *bytes); static PyObject * -bytearray_lstrip(PyByteArrayObject *self, PyObject *args) +bytearray_lstrip(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *bytes = Py_None; - if (!PyArg_UnpackTuple(args, "lstrip", + if (!_PyArg_UnpackStack(args, nargs, "lstrip", 0, 1, &bytes)) { goto exit; } + + if (!_PyArg_NoStackKeywords("lstrip", kwnames)) { + goto exit; + } return_value = bytearray_lstrip_impl(self, bytes); exit: @@ -525,22 +533,26 @@ PyDoc_STRVAR(bytearray_rstrip__doc__, "If the argument is omitted or None, strip trailing ASCII whitespace."); #define BYTEARRAY_RSTRIP_METHODDEF \ - {"rstrip", (PyCFunction)bytearray_rstrip, METH_VARARGS, bytearray_rstrip__doc__}, + {"rstrip", (PyCFunction)bytearray_rstrip, METH_FASTCALL, bytearray_rstrip__doc__}, static PyObject * bytearray_rstrip_impl(PyByteArrayObject *self, PyObject *bytes); static PyObject * -bytearray_rstrip(PyByteArrayObject *self, PyObject *args) +bytearray_rstrip(PyByteArrayObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *bytes = Py_None; - if (!PyArg_UnpackTuple(args, "rstrip", + if (!_PyArg_UnpackStack(args, nargs, "rstrip", 0, 1, &bytes)) { goto exit; } + + if (!_PyArg_NoStackKeywords("rstrip", kwnames)) { + goto exit; + } return_value = bytearray_rstrip_impl(self, bytes); exit: @@ -731,4 +743,4 @@ bytearray_sizeof(PyByteArrayObject *self, PyObject *Py_UNUSED(ignored)) { return bytearray_sizeof_impl(self); } -/*[clinic end generated code: output=e6c057d1cd7c2496 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f5c364927425fae8 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/bytesobject.c.h b/Objects/clinic/bytesobject.c.h index 330cb84853..c73b56023d 100644 --- a/Objects/clinic/bytesobject.c.h +++ b/Objects/clinic/bytesobject.c.h @@ -184,22 +184,26 @@ PyDoc_STRVAR(bytes_strip__doc__, "If the argument is omitted or None, strip leading and trailing ASCII whitespace."); #define BYTES_STRIP_METHODDEF \ - {"strip", (PyCFunction)bytes_strip, METH_VARARGS, bytes_strip__doc__}, + {"strip", (PyCFunction)bytes_strip, METH_FASTCALL, bytes_strip__doc__}, static PyObject * bytes_strip_impl(PyBytesObject *self, PyObject *bytes); static PyObject * -bytes_strip(PyBytesObject *self, PyObject *args) +bytes_strip(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *bytes = Py_None; - if (!PyArg_UnpackTuple(args, "strip", + if (!_PyArg_UnpackStack(args, nargs, "strip", 0, 1, &bytes)) { goto exit; } + + if (!_PyArg_NoStackKeywords("strip", kwnames)) { + goto exit; + } return_value = bytes_strip_impl(self, bytes); exit: @@ -215,22 +219,26 @@ PyDoc_STRVAR(bytes_lstrip__doc__, "If the argument is omitted or None, strip leading ASCII whitespace."); #define BYTES_LSTRIP_METHODDEF \ - {"lstrip", (PyCFunction)bytes_lstrip, METH_VARARGS, bytes_lstrip__doc__}, + {"lstrip", (PyCFunction)bytes_lstrip, METH_FASTCALL, bytes_lstrip__doc__}, static PyObject * bytes_lstrip_impl(PyBytesObject *self, PyObject *bytes); static PyObject * -bytes_lstrip(PyBytesObject *self, PyObject *args) +bytes_lstrip(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *bytes = Py_None; - if (!PyArg_UnpackTuple(args, "lstrip", + if (!_PyArg_UnpackStack(args, nargs, "lstrip", 0, 1, &bytes)) { goto exit; } + + if (!_PyArg_NoStackKeywords("lstrip", kwnames)) { + goto exit; + } return_value = bytes_lstrip_impl(self, bytes); exit: @@ -246,22 +254,26 @@ PyDoc_STRVAR(bytes_rstrip__doc__, "If the argument is omitted or None, strip trailing ASCII whitespace."); #define BYTES_RSTRIP_METHODDEF \ - {"rstrip", (PyCFunction)bytes_rstrip, METH_VARARGS, bytes_rstrip__doc__}, + {"rstrip", (PyCFunction)bytes_rstrip, METH_FASTCALL, bytes_rstrip__doc__}, static PyObject * bytes_rstrip_impl(PyBytesObject *self, PyObject *bytes); static PyObject * -bytes_rstrip(PyBytesObject *self, PyObject *args) +bytes_rstrip(PyBytesObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *bytes = Py_None; - if (!PyArg_UnpackTuple(args, "rstrip", + if (!_PyArg_UnpackStack(args, nargs, "rstrip", 0, 1, &bytes)) { goto exit; } + + if (!_PyArg_NoStackKeywords("rstrip", kwnames)) { + goto exit; + } return_value = bytes_rstrip_impl(self, bytes); exit: @@ -507,4 +519,4 @@ bytes_fromhex(PyTypeObject *type, PyObject *arg) exit: return return_value; } -/*[clinic end generated code: output=2b8d3cff7e11045e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2504c1225108d348 input=a9049054013a1b77]*/ diff --git a/Objects/clinic/dictobject.c.h b/Objects/clinic/dictobject.c.h index d0cdfc3eda..3f06c0b5da 100644 --- a/Objects/clinic/dictobject.c.h +++ b/Objects/clinic/dictobject.c.h @@ -9,23 +9,27 @@ PyDoc_STRVAR(dict_fromkeys__doc__, "Returns a new dict with keys from iterable and values equal to value."); #define DICT_FROMKEYS_METHODDEF \ - {"fromkeys", (PyCFunction)dict_fromkeys, METH_VARARGS|METH_CLASS, dict_fromkeys__doc__}, + {"fromkeys", (PyCFunction)dict_fromkeys, METH_FASTCALL|METH_CLASS, dict_fromkeys__doc__}, static PyObject * dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value); static PyObject * -dict_fromkeys(PyTypeObject *type, PyObject *args) +dict_fromkeys(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *iterable; PyObject *value = Py_None; - if (!PyArg_UnpackTuple(args, "fromkeys", + if (!_PyArg_UnpackStack(args, nargs, "fromkeys", 1, 2, &iterable, &value)) { goto exit; } + + if (!_PyArg_NoStackKeywords("fromkeys", kwnames)) { + goto exit; + } return_value = dict_fromkeys_impl(type, iterable, value); exit: @@ -40,4 +44,4 @@ PyDoc_STRVAR(dict___contains____doc__, #define DICT___CONTAINS___METHODDEF \ {"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__}, -/*[clinic end generated code: output=926326109e3d9839 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=69f3d767ed44e8ec input=a9049054013a1b77]*/ diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index d968cbe346..c4bf3a433c 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -471,27 +471,31 @@ PyDoc_STRVAR(unicode_strip__doc__, "strip($self, chars=None, /)\n" "--\n" "\n" -"Return a copy of the string with leading and trailing whitespace removed.\n" +"Return a copy of the string with leading and trailing whitespace remove.\n" "\n" "If chars is given and not None, remove characters in chars instead."); #define UNICODE_STRIP_METHODDEF \ - {"strip", (PyCFunction)unicode_strip, METH_VARARGS, unicode_strip__doc__}, + {"strip", (PyCFunction)unicode_strip, METH_FASTCALL, unicode_strip__doc__}, static PyObject * unicode_strip_impl(PyObject *self, PyObject *chars); static PyObject * -unicode_strip(PyObject *self, PyObject *args) +unicode_strip(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *chars = Py_None; - if (!PyArg_UnpackTuple(args, "strip", + if (!_PyArg_UnpackStack(args, nargs, "strip", 0, 1, &chars)) { goto exit; } + + if (!_PyArg_NoStackKeywords("strip", kwnames)) { + goto exit; + } return_value = unicode_strip_impl(self, chars); exit: @@ -507,22 +511,26 @@ PyDoc_STRVAR(unicode_lstrip__doc__, "If chars is given and not None, remove characters in chars instead."); #define UNICODE_LSTRIP_METHODDEF \ - {"lstrip", (PyCFunction)unicode_lstrip, METH_VARARGS, unicode_lstrip__doc__}, + {"lstrip", (PyCFunction)unicode_lstrip, METH_FASTCALL, unicode_lstrip__doc__}, static PyObject * unicode_lstrip_impl(PyObject *self, PyObject *chars); static PyObject * -unicode_lstrip(PyObject *self, PyObject *args) +unicode_lstrip(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *chars = NULL; - if (!PyArg_UnpackTuple(args, "lstrip", + if (!_PyArg_UnpackStack(args, nargs, "lstrip", 0, 1, &chars)) { goto exit; } + + if (!_PyArg_NoStackKeywords("lstrip", kwnames)) { + goto exit; + } return_value = unicode_lstrip_impl(self, chars); exit: @@ -538,22 +546,26 @@ PyDoc_STRVAR(unicode_rstrip__doc__, "If chars is given and not None, remove characters in chars instead."); #define UNICODE_RSTRIP_METHODDEF \ - {"rstrip", (PyCFunction)unicode_rstrip, METH_VARARGS, unicode_rstrip__doc__}, + {"rstrip", (PyCFunction)unicode_rstrip, METH_FASTCALL, unicode_rstrip__doc__}, static PyObject * unicode_rstrip_impl(PyObject *self, PyObject *chars); static PyObject * -unicode_rstrip(PyObject *self, PyObject *args) +unicode_rstrip(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *chars = NULL; - if (!PyArg_UnpackTuple(args, "rstrip", + if (!_PyArg_UnpackStack(args, nargs, "rstrip", 0, 1, &chars)) { goto exit; } + + if (!_PyArg_NoStackKeywords("rstrip", kwnames)) { + goto exit; + } return_value = unicode_rstrip_impl(self, chars); exit: @@ -950,4 +962,4 @@ unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) { return unicode_sizeof_impl(self); } -/*[clinic end generated code: output=eb6a3ae361a1a379 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=3d73f3dfd6ec7d83 input=a9049054013a1b77]*/ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index e2bdf088ab..5fbe56cce1 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -12453,14 +12453,14 @@ str.strip as unicode_strip chars: object = None / -Return a copy of the string with leading and trailing whitespace removed. +Return a copy of the string with leading and trailing whitespace remove. If chars is given and not None, remove characters in chars instead. [clinic start generated code]*/ static PyObject * unicode_strip_impl(PyObject *self, PyObject *chars) -/*[clinic end generated code: output=ca19018454345d57 input=385289c6f423b954]*/ +/*[clinic end generated code: output=ca19018454345d57 input=eefe24a1059c352b]*/ { return do_argstrip(self, BOTHSTRIP, chars); } -- cgit v1.2.1 From 6f60ffbcc042a8ee070e9f254d5f016a0467eda6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 17 Jan 2017 03:46:13 +0100 Subject: Convert some OrderedDict methods to Argument Clinic Issue #29289. Convert methods: * fromkeys() class method * setdefault() * popitem() * move_to_end() --- Objects/clinic/odictobject.c.h | 135 ++++++++++++++++++++++++++++++++ Objects/odictobject.c | 171 ++++++++++++++++++++--------------------- 2 files changed, 219 insertions(+), 87 deletions(-) create mode 100644 Objects/clinic/odictobject.c.h (limited to 'Objects') diff --git a/Objects/clinic/odictobject.c.h b/Objects/clinic/odictobject.c.h new file mode 100644 index 0000000000..5543f9463e --- /dev/null +++ b/Objects/clinic/odictobject.c.h @@ -0,0 +1,135 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(OrderedDict_fromkeys__doc__, +"fromkeys($type, /, iterable, value=None)\n" +"--\n" +"\n" +"New ordered dictionary with keys from S.\n" +"\n" +"If not specified, the value defaults to None."); + +#define ORDEREDDICT_FROMKEYS_METHODDEF \ + {"fromkeys", (PyCFunction)OrderedDict_fromkeys, METH_FASTCALL|METH_CLASS, OrderedDict_fromkeys__doc__}, + +static PyObject * +OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value); + +static PyObject * +OrderedDict_fromkeys(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"iterable", "value", NULL}; + static _PyArg_Parser _parser = {"O|O:fromkeys", _keywords, 0}; + PyObject *seq; + PyObject *value = Py_None; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &seq, &value)) { + goto exit; + } + return_value = OrderedDict_fromkeys_impl(type, seq, value); + +exit: + return return_value; +} + +PyDoc_STRVAR(OrderedDict_setdefault__doc__, +"setdefault($self, /, key, default=None)\n" +"--\n" +"\n" +"od.get(k,d), also set od[k]=d if k not in od."); + +#define ORDEREDDICT_SETDEFAULT_METHODDEF \ + {"setdefault", (PyCFunction)OrderedDict_setdefault, METH_FASTCALL, OrderedDict_setdefault__doc__}, + +static PyObject * +OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, + PyObject *failobj); + +static PyObject * +OrderedDict_setdefault(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"key", "default", NULL}; + static _PyArg_Parser _parser = {"O|O:setdefault", _keywords, 0}; + PyObject *key; + PyObject *failobj = Py_None; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &key, &failobj)) { + goto exit; + } + return_value = OrderedDict_setdefault_impl(self, key, failobj); + +exit: + return return_value; +} + +PyDoc_STRVAR(OrderedDict_popitem__doc__, +"popitem($self, /, last=True)\n" +"--\n" +"\n" +"Return (k, v) and remove a (key, value) pair.\n" +"\n" +"Pairs are returned in LIFO order if last is true or FIFO order if false."); + +#define ORDEREDDICT_POPITEM_METHODDEF \ + {"popitem", (PyCFunction)OrderedDict_popitem, METH_FASTCALL, OrderedDict_popitem__doc__}, + +static PyObject * +OrderedDict_popitem_impl(PyODictObject *self, int last); + +static PyObject * +OrderedDict_popitem(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"last", NULL}; + static _PyArg_Parser _parser = {"|p:popitem", _keywords, 0}; + int last = 1; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &last)) { + goto exit; + } + return_value = OrderedDict_popitem_impl(self, last); + +exit: + return return_value; +} + +PyDoc_STRVAR(OrderedDict_move_to_end__doc__, +"move_to_end($self, /, key, last=True)\n" +"--\n" +"\n" +"\"Move an existing element to the end (or beginning if last==False).\n" +"\n" +" Raises KeyError if the element does not exist.\n" +" When last=True, acts like a fast version of self[key]=self.pop(key)."); + +#define ORDEREDDICT_MOVE_TO_END_METHODDEF \ + {"move_to_end", (PyCFunction)OrderedDict_move_to_end, METH_FASTCALL, OrderedDict_move_to_end__doc__}, + +static PyObject * +OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last); + +static PyObject * +OrderedDict_move_to_end(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"key", "last", NULL}; + static _PyArg_Parser _parser = {"O|p:move_to_end", _keywords, 0}; + PyObject *key; + int last = 1; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &key, &last)) { + goto exit; + } + return_value = OrderedDict_move_to_end_impl(self, key, last); + +exit: + return return_value; +} +/*[clinic end generated code: output=f2641e1277045b59 input=a9049054013a1b77]*/ diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 5833df5f72..aac454c817 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -474,6 +474,13 @@ later: #include "dict-common.h" #include +#include "clinic/odictobject.c.h" + +/*[clinic input] +class OrderedDict "PyODictObject *" "&PyODict_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ca0641cf6143d4af]*/ + typedef struct _odictnode _ODictNode; @@ -912,25 +919,23 @@ PyDoc_STRVAR(odict_setitem__doc__, "od.__setitem__(i, y) <==> od[i]=y"); /* fromkeys() */ -PyDoc_STRVAR(odict_fromkeys__doc__, -"OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S.\n\ - If not specified, the value defaults to None.\n\ -\n\ - "); +/*[clinic input] +@classmethod +OrderedDict.fromkeys + + iterable as seq: object + value: object = None + +New ordered dictionary with keys from S. + +If not specified, the value defaults to None. +[clinic start generated code]*/ static PyObject * -odict_fromkeys(PyObject *cls, PyObject *args, PyObject *kwargs) +OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value) +/*[clinic end generated code: output=c10390d452d78d6d input=33eefc496d5eee7b]*/ { - static char *kwlist[] = {"iterable", "value", 0}; - PyObject *seq; - PyObject *value = Py_None; - - /* both borrowed */ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:fromkeys", kwlist, - &seq, &value)) { - return NULL; - } - return _PyDict_FromKeys(cls, seq, value); + return _PyDict_FromKeys((PyObject *)type, seq, value); } /* __sizeof__() */ @@ -1000,32 +1005,32 @@ Done: return result; } -/* setdefault() */ +/* setdefault(): Skips __missing__() calls. */ -PyDoc_STRVAR(odict_setdefault__doc__, - "od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od"); -/* Skips __missing__() calls. */ +/*[clinic input] +OrderedDict.setdefault + + key: object + default as failobj: object = None + +od.get(k,d), also set od[k]=d if k not in od. +[clinic start generated code]*/ + static PyObject * -odict_setdefault(register PyODictObject *od, PyObject *args, PyObject *kwargs) +OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, + PyObject *failobj) +/*[clinic end generated code: output=605d0f6f61ccb0a6 input=4ee5006f32f5691b]*/ { - static char *kwlist[] = {"key", "default", 0}; - PyObject *key, *result = NULL; - PyObject *failobj = Py_None; + PyObject *result = NULL; - /* both borrowed */ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O:setdefault", kwlist, - &key, &failobj)) { - return NULL; - } - - if (PyODict_CheckExact(od)) { - result = PyODict_GetItemWithError(od, key); /* borrowed */ + if (PyODict_CheckExact(self)) { + result = PyODict_GetItemWithError(self, key); /* borrowed */ if (result == NULL) { if (PyErr_Occurred()) return NULL; - assert(_odict_find_node(od, key) == NULL); - if (PyODict_SetItem((PyObject *)od, key, failobj) >= 0) { + assert(_odict_find_node(self, key) == NULL); + if (PyODict_SetItem((PyObject *)self, key, failobj) >= 0) { result = failobj; Py_INCREF(failobj); } @@ -1035,14 +1040,14 @@ odict_setdefault(register PyODictObject *od, PyObject *args, PyObject *kwargs) } } else { - int exists = PySequence_Contains((PyObject *)od, key); + int exists = PySequence_Contains((PyObject *)self, key); if (exists < 0) { return NULL; } else if (exists) { - result = PyObject_GetItem((PyObject *)od, key); + result = PyObject_GetItem((PyObject *)self, key); } - else if (PyObject_SetItem((PyObject *)od, key, failobj) >= 0) { + else if (PyObject_SetItem((PyObject *)self, key, failobj) >= 0) { result = failobj; Py_INCREF(failobj); } @@ -1152,39 +1157,37 @@ _odict_popkey(PyObject *od, PyObject *key, PyObject *failobj) return _odict_popkey_hash(od, key, failobj, hash); } + /* popitem() */ -PyDoc_STRVAR(odict_popitem__doc__, -"od.popitem() -> (k, v), return and remove a (key, value) pair.\n\ - Pairs are returned in LIFO order if last is true or FIFO order if false.\n\ -\n\ - "); +/*[clinic input] +OrderedDict.popitem + + last: bool = True + +Return (k, v) and remove a (key, value) pair. + +Pairs are returned in LIFO order if last is true or FIFO order if false. +[clinic start generated code]*/ static PyObject * -odict_popitem(PyObject *od, PyObject *args, PyObject *kwargs) +OrderedDict_popitem_impl(PyODictObject *self, int last) +/*[clinic end generated code: output=98e7d986690d49eb input=4937da2015939126]*/ { - static char *kwlist[] = {"last", 0}; PyObject *key, *value, *item = NULL; _ODictNode *node; - int last = 1; /* pull the item */ - /* borrowed */ - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|p:popitem", kwlist, - &last)) { - return NULL; - } - - if (_odict_EMPTY(od)) { + if (_odict_EMPTY(self)) { PyErr_SetString(PyExc_KeyError, "dictionary is empty"); return NULL; } - node = last ? _odict_LAST(od) : _odict_FIRST(od); + node = last ? _odict_LAST(self) : _odict_FIRST(self); key = _odictnode_KEY(node); Py_INCREF(key); - value = _odict_popkey_hash(od, key, NULL, _odictnode_HASH(node)); + value = _odict_popkey_hash((PyObject *)self, key, NULL, _odictnode_HASH(node)); if (value == NULL) return NULL; item = PyTuple_Pack(2, key, value); @@ -1312,36 +1315,34 @@ odict_reversed(PyODictObject *od) return odictiter_new(od, _odict_ITER_KEYS|_odict_ITER_REVERSED); } + /* move_to_end() */ -PyDoc_STRVAR(odict_move_to_end__doc__, -"Move an existing element to the end (or beginning if last==False).\n\ -\n\ - Raises KeyError if the element does not exist.\n\ - When last=True, acts like a fast version of self[key]=self.pop(key).\n\ -\n\ - "); +/*[clinic input] +OrderedDict.move_to_end + + key: object + last: bool = True + +"Move an existing element to the end (or beginning if last==False). + + Raises KeyError if the element does not exist. + When last=True, acts like a fast version of self[key]=self.pop(key). +[clinic start generated code]*/ static PyObject * -odict_move_to_end(PyODictObject *od, PyObject *args, PyObject *kwargs) +OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last) +/*[clinic end generated code: output=fafa4c5cc9b92f20 input=3b8283f7d0e15e43]*/ { - static char *kwlist[] = {"key", "last", 0}; - PyObject *key; - int last = 1; _ODictNode *node; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|p:move_to_end", kwlist, - &key, &last)) { - return NULL; - } - - if (_odict_EMPTY(od)) { + if (_odict_EMPTY(self)) { PyErr_SetObject(PyExc_KeyError, key); return NULL; } - node = last ? _odict_LAST(od) : _odict_FIRST(od); + node = last ? _odict_LAST(self) : _odict_FIRST(self); if (key != _odictnode_KEY(node)) { - node = _odict_find_node(od, key); + node = _odict_find_node(self, key); if (node == NULL) { if (!PyErr_Occurred()) PyErr_SetObject(PyExc_KeyError, key); @@ -1349,16 +1350,16 @@ odict_move_to_end(PyODictObject *od, PyObject *args, PyObject *kwargs) } if (last) { /* Only move if not already the last one. */ - if (node != _odict_LAST(od)) { - _odict_remove_node(od, node); - _odict_add_tail(od, node); + if (node != _odict_LAST(self)) { + _odict_remove_node(self, node); + _odict_add_tail(self, node); } } else { /* Only move if not already the first one. */ - if (node != _odict_FIRST(od)) { - _odict_remove_node(od, node); - _odict_add_head(od, node); + if (node != _odict_FIRST(self)) { + _odict_remove_node(self, node); + _odict_add_head(self, node); } } } @@ -1386,20 +1387,17 @@ static PyMethodDef odict_methods[] = { odict_repr__doc__}, {"__setitem__", (PyCFunction)odict_mp_ass_sub, METH_NOARGS, odict_setitem__doc__}, - {"fromkeys", (PyCFunction)odict_fromkeys, - METH_VARARGS | METH_KEYWORDS | METH_CLASS, odict_fromkeys__doc__}, + ORDEREDDICT_FROMKEYS_METHODDEF /* overridden dict methods */ {"__sizeof__", (PyCFunction)odict_sizeof, METH_NOARGS, odict_sizeof__doc__}, {"__reduce__", (PyCFunction)odict_reduce, METH_NOARGS, odict_reduce__doc__}, - {"setdefault", (PyCFunction)odict_setdefault, - METH_VARARGS | METH_KEYWORDS, odict_setdefault__doc__}, + ORDEREDDICT_SETDEFAULT_METHODDEF {"pop", (PyCFunction)odict_pop, METH_VARARGS | METH_KEYWORDS, odict_pop__doc__}, - {"popitem", (PyCFunction)odict_popitem, - METH_VARARGS | METH_KEYWORDS, odict_popitem__doc__}, + ORDEREDDICT_POPITEM_METHODDEF {"keys", (PyCFunction)odictkeys_new, METH_NOARGS, odict_keys__doc__}, {"values", (PyCFunction)odictvalues_new, METH_NOARGS, @@ -1416,8 +1414,7 @@ static PyMethodDef odict_methods[] = { /* new methods */ {"__reversed__", (PyCFunction)odict_reversed, METH_NOARGS, odict_reversed__doc__}, - {"move_to_end", (PyCFunction)odict_move_to_end, - METH_VARARGS | METH_KEYWORDS, odict_move_to_end__doc__}, + ORDEREDDICT_MOVE_TO_END_METHODDEF {NULL, NULL} /* sentinel */ }; -- cgit v1.2.1 From e44ae9a7fd3a32fc03338559f82679db3e6f79fd Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Jan 2017 10:31:46 +0100 Subject: Remove unused func parameter of _PyStack_UnpackDict() Issue #29259. --- Objects/abstract.c | 2 +- Objects/methodobject.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index ee50f02057..682263d7bc 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2423,7 +2423,7 @@ _PyStack_AsDict(PyObject **values, PyObject *kwnames) int _PyStack_UnpackDict(PyObject **args, Py_ssize_t nargs, PyObject *kwargs, - PyObject ***p_stack, PyObject **p_kwnames, PyObject *func) + PyObject ***p_stack, PyObject **p_kwnames) { PyObject **stack, **kwstack; Py_ssize_t nkwargs; diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 7bff6a037b..1d55a0cd48 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -240,8 +240,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, PyObject *kwnames; _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; - if (_PyStack_UnpackDict(args, nargs, kwargs, - &stack, &kwnames, func_obj) < 0) { + if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) { return NULL; } -- cgit v1.2.1 From b789d9fab8fd9c88b4463b5060034400937e8433 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Jan 2017 10:38:09 +0100 Subject: Optimize methoddescr_call(): avoid temporary PyCFunction Issue #29259, #29263. methoddescr_call() creates a PyCFunction object, call it and the destroy it. Add a new _PyMethodDef_RawFastCallDict() method to avoid the temporary PyCFunction object. --- Objects/descrobject.c | 20 +++++++++----------- Objects/methodobject.c | 39 ++++++++++++++++++++++++--------------- 2 files changed, 33 insertions(+), 26 deletions(-) (limited to 'Objects') diff --git a/Objects/descrobject.c b/Objects/descrobject.c index ed398919a3..a254a2a673 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -210,15 +210,15 @@ getset_set(PyGetSetDescrObject *descr, PyObject *obj, PyObject *value) } static PyObject * -methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) +methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs) { - Py_ssize_t argc; - PyObject *self, *func, *result, **stack; + Py_ssize_t nargs; + PyObject *self, *result; /* Make sure that the first argument is acceptable as 'self' */ assert(PyTuple_Check(args)); - argc = PyTuple_GET_SIZE(args); - if (argc < 1) { + nargs = PyTuple_GET_SIZE(args); + if (nargs < 1) { PyErr_Format(PyExc_TypeError, "descriptor '%V' of '%.100s' " "object needs an argument", @@ -239,12 +239,10 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) return NULL; } - func = PyCFunction_NewEx(descr->d_method, self, NULL); - if (func == NULL) - return NULL; - stack = &PyTuple_GET_ITEM(args, 1); - result = _PyObject_FastCallDict(func, stack, argc - 1, kwds); - Py_DECREF(func); + result = _PyMethodDef_RawFastCallDict(descr->d_method, self, + &PyTuple_GET_ITEM(args, 1), nargs - 1, + kwargs); + result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL); return result; } diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 1d55a0cd48..054cf530e4 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -152,17 +152,14 @@ PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) } PyObject * -_PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, - PyObject *kwargs) +_PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args, + Py_ssize_t nargs, PyObject *kwargs) { - PyCFunctionObject *func; PyCFunction meth; - PyObject *self; PyObject *result; int flags; - assert(func_obj != NULL); - assert(PyCFunction_Check(func_obj)); + assert(method != NULL); assert(nargs >= 0); assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); @@ -172,10 +169,8 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, caller loses its exception */ assert(!PyErr_Occurred()); - func = (PyCFunctionObject*)func_obj; - meth = PyCFunction_GET_FUNCTION(func); - self = PyCFunction_GET_SELF(func); - flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + meth = method->ml_meth; + flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); switch (flags) { @@ -186,7 +181,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - func->m_ml->ml_name); + method->ml_name); return NULL; } @@ -197,7 +192,7 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, if (nargs != 1) { PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", - func->m_ml->ml_name, nargs); + method->ml_name, nargs); return NULL; } @@ -259,17 +254,31 @@ _PyCFunction_FastCallDict(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, return NULL; } - result = _Py_CheckFunctionResult(func_obj, result, NULL); - return result; no_keyword_error: PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", - func->m_ml->ml_name, nargs); + method->ml_name, nargs); return NULL; } +PyObject * +_PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, + PyObject *kwargs) +{ + PyObject *result; + + assert(func != NULL); + assert(PyCFunction_Check(func)); + + result = _PyMethodDef_RawFastCallDict(((PyCFunctionObject*)func)->m_ml, + PyCFunction_GET_SELF(func), + args, nargs, kwargs); + result = _Py_CheckFunctionResult(func, result, NULL); + return result; +} + PyObject * _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) -- cgit v1.2.1 From 1e87b169d0aabb2b52f5d642b96dbb60b41310f1 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Jan 2017 11:27:22 +0100 Subject: _PyObject_FastCallKeywords() now checks the result Issue ##27830, Issue #29259. --- Objects/abstract.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 682263d7bc..4b32fedccf 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2539,6 +2539,8 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg Py_DECREF(argtuple); Py_XDECREF(kwdict); + result = _Py_CheckFunctionResult(callable, result, NULL); + exit: Py_LeaveRecursiveCall(); return result; -- cgit v1.2.1 From b9c6df9ebf5150b8c0657a588c6ccc7c060da1c8 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Jan 2017 14:01:12 +0100 Subject: Fix _PyMethodDef_RawFastCallDict() argument parsing Issue #29259: * Move also the !PyErr_Occurred() assertion to the top, similar to other functions. * Fix also comment/error messages: the function was renamed to _PyMethodDef_RawFastCallDict() --- Objects/methodobject.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'Objects') diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 054cf530e4..19d2971b9b 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -159,30 +159,31 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg PyObject *result; int flags; + /* _PyMethodDef_RawFastCallDict() must not be called with an exception set, + because it may clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + assert(method != NULL); assert(nargs >= 0); assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); - /* _PyCFunction_FastCallDict() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!PyErr_Occurred()); - meth = method->ml_meth; flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); switch (flags) { case METH_NOARGS: - if (nargs != 0) { - goto no_keyword_error; - } + if (nargs != 0) { + PyErr_Format(PyExc_TypeError, + "%.200s() takes no arguments (%zd given)", + method->ml_name, nargs); + return NULL; + } if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { - PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - method->ml_name); - return NULL; + goto no_keyword_error; } result = (*meth) (self, NULL); @@ -249,7 +250,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg default: PyErr_SetString(PyExc_SystemError, - "Bad call flags in PyCFunction_Call. " + "Bad call flags in _PyMethodDef_RawFastCallDict. " "METH_OLDARGS is no longer supported!"); return NULL; } @@ -258,8 +259,9 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg no_keyword_error: PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", - method->ml_name, nargs); + "%.200s() takes no keyword arguments", + method->ml_name, nargs); + return NULL; } -- cgit v1.2.1 From 0d1ea345cf7da0978f5cb8e76a843506a8278a39 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Jan 2017 14:04:37 +0100 Subject: PyCFunction_Call() now calls _PyCFunction_FastCallDict() Issue #29259. We had 3 versions of similar code: * PyCFunction_Call() * _PyCFunction_FastCallDict() * _PyCFunction_FastCallKeywords() PyCFunction_Call() now calls _PyCFunction_FastCallDict() to factorize the code. --- Objects/methodobject.c | 75 ++++---------------------------------------------- 1 file changed, 5 insertions(+), 70 deletions(-) (limited to 'Objects') diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 19d2971b9b..5331cfb319 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -78,77 +78,12 @@ PyCFunction_GetFlags(PyObject *op) } PyObject * -PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwds) +PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) { - PyCFunctionObject* f = (PyCFunctionObject*)func; - PyCFunction meth = PyCFunction_GET_FUNCTION(func); - PyObject *self = PyCFunction_GET_SELF(func); - PyObject *arg, *res; - Py_ssize_t size; - int flags; - - assert(kwds == NULL || PyDict_Check(kwds)); - /* PyCFunction_Call() must not be called with an exception set, - because it can clear it (directly or indirectly) and so the - caller loses its exception */ - assert(!PyErr_Occurred()); - - flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); - - if (flags == (METH_VARARGS | METH_KEYWORDS)) { - res = (*(PyCFunctionWithKeywords)meth)(self, args, kwds); - } - else if (flags == METH_FASTCALL) { - PyObject **stack = &PyTuple_GET_ITEM(args, 0); - Py_ssize_t nargs = PyTuple_GET_SIZE(args); - res = _PyCFunction_FastCallDict(func, stack, nargs, kwds); - } - else { - if (kwds != NULL && PyDict_GET_SIZE(kwds) != 0) { - PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - f->m_ml->ml_name); - return NULL; - } - - switch (flags) { - case METH_VARARGS: - res = (*meth)(self, args); - break; - - case METH_NOARGS: - size = PyTuple_GET_SIZE(args); - if (size != 0) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes no arguments (%zd given)", - f->m_ml->ml_name, size); - return NULL; - } - - res = (*meth)(self, NULL); - break; - - case METH_O: - size = PyTuple_GET_SIZE(args); - if (size != 1) { - PyErr_Format(PyExc_TypeError, - "%.200s() takes exactly one argument (%zd given)", - f->m_ml->ml_name, size); - return NULL; - } - - arg = PyTuple_GET_ITEM(args, 0); - res = (*meth)(self, arg); - break; - - default: - PyErr_SetString(PyExc_SystemError, - "Bad call flags in PyCFunction_Call. " - "METH_OLDARGS is no longer supported!"); - return NULL; - } - } - - return _Py_CheckFunctionResult(func, res, NULL); + return _PyCFunction_FastCallDict(func, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args), + kwargs); } PyObject * -- cgit v1.2.1 From 74d6d9a64feed656f54ca069e3ccc6e4bf1db270 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Jan 2017 14:06:38 +0100 Subject: _PyObject_FastCallKeywords() now checks !PyErr_Occurred() Issue #29259. All other functions calling functions start with the similar assertion. --- Objects/abstract.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 4b32fedccf..1132b842ca 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2482,6 +2482,11 @@ PyObject * _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t nargs, PyObject *kwnames) { + /* _PyObject_FastCallKeywords() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); + assert(nargs >= 0); assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); -- cgit v1.2.1 From 4a6bc8201521488a56ced3d3825e21915f681fae Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Jan 2017 14:12:51 +0100 Subject: Rephrase !PyErr_Occurred() comment: may=>can Issue #29259. --- Objects/abstract.c | 4 ++-- Objects/methodobject.c | 2 +- Objects/object.c | 4 ++-- Objects/typeobject.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 1132b842ca..7b1f196891 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2233,7 +2233,7 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) PyObject *result; /* PyObject_Call() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the + because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!PyErr_Occurred()); assert(PyTuple_Check(args)); @@ -2309,7 +2309,7 @@ _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, PyObject *result = NULL; /* _PyObject_FastCallDict() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the + because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!PyErr_Occurred()); diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 5331cfb319..ebea8b3d50 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -95,7 +95,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg int flags; /* _PyMethodDef_RawFastCallDict() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the + because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!PyErr_Occurred()); diff --git a/Objects/object.c b/Objects/object.c index dc50131e3f..7b80bcb91d 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -477,7 +477,7 @@ PyObject_Repr(PyObject *v) #ifdef Py_DEBUG /* PyObject_Repr() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the + because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!PyErr_Occurred()); #endif @@ -526,7 +526,7 @@ PyObject_Str(PyObject *v) #ifdef Py_DEBUG /* PyObject_Str() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the + because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!PyErr_Occurred()); #endif diff --git a/Objects/typeobject.c b/Objects/typeobject.c index a521177210..0fdff318b8 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -887,7 +887,7 @@ type_call(PyTypeObject *type, PyObject *args, PyObject *kwds) #ifdef Py_DEBUG /* type_call() must not be called with an exception set, - because it may clear it (directly or indirectly) and so the + because it can clear it (directly or indirectly) and so the caller loses its exception */ assert(!PyErr_Occurred()); #endif -- cgit v1.2.1 From 807baefab55327c47a01cb3136b36d8ef6bc5e0e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Jan 2017 14:16:57 +0100 Subject: Cleanup _PyMethodDef_RawFastCallDict() Issue #29259: use a different case for METH_VARARGS and METH_VARARGS|METH_KEYWORDS to avoid testing again flags to decide if keywords should be checked or not. --- Objects/methodobject.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'Objects') diff --git a/Objects/methodobject.c b/Objects/methodobject.c index ebea8b3d50..35a827e164 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -93,6 +93,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg PyCFunction meth; PyObject *result; int flags; + PyObject *argstuple; /* _PyMethodDef_RawFastCallDict() must not be called with an exception set, because it can clear it (directly or indirectly) and so the @@ -140,30 +141,27 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg break; case METH_VARARGS: - case METH_VARARGS | METH_KEYWORDS: - { - /* Slow-path: create a temporary tuple for positional arguments */ - PyObject *tuple; - if (!(flags & METH_KEYWORDS) && kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { goto no_keyword_error; } + /* fall through next case */ - tuple = _PyStack_AsTuple(args, nargs); - if (tuple == NULL) { + case METH_VARARGS | METH_KEYWORDS: + /* Slow-path: create a temporary tuple for positional arguments */ + argstuple = _PyStack_AsTuple(args, nargs); + if (argstuple == NULL) { return NULL; } if (flags & METH_KEYWORDS) { - result = (*(PyCFunctionWithKeywords)meth) (self, tuple, kwargs); + result = (*(PyCFunctionWithKeywords)meth) (self, argstuple, kwargs); } else { - result = (*meth) (self, tuple); + result = (*meth) (self, argstuple); } - Py_DECREF(tuple); + Py_DECREF(argstuple); break; - } case METH_FASTCALL: { -- cgit v1.2.1 From abe9d8370c190416822dbc329872de805219caf6 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Jan 2017 18:06:32 +0100 Subject: _PyStack_AsDict() now checks kwnames != NULL Issue #29259. --- Objects/abstract.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 7b1f196891..58640323dc 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2399,10 +2399,12 @@ _PyObject_Call_Prepend(PyObject *callable, PyObject * _PyStack_AsDict(PyObject **values, PyObject *kwnames) { - Py_ssize_t nkwargs = PyTuple_GET_SIZE(kwnames); + Py_ssize_t nkwargs; PyObject *kwdict; Py_ssize_t i; + assert(kwnames != NULL); + nkwargs = PyTuple_GET_SIZE(kwnames); kwdict = _PyDict_NewPresized(nkwargs); if (kwdict == NULL) { return NULL; -- cgit v1.2.1 From 2b51b5bb59545d275d04fe958f4d347cb2508027 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 19 Jan 2017 12:37:13 +0100 Subject: dict.get() and dict.setdefault() now use AC Issue #29311: dict.get() and dict.setdefault() methods now use Argument Clinic to parse arguments. Their calling convention changes from METH_VARARGS to METH_FASTCALL which avoids the creation of a temporary tuple. The signature of docstrings is also enhanced. For example, get(...) becomes: get(self, key, default=None, /) --- Objects/clinic/dictobject.c.h | 70 ++++++++++++++++++++++++++++++++++++++++++- Objects/dictobject.c | 53 +++++++++++++++++--------------- 2 files changed, 98 insertions(+), 25 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/dictobject.c.h b/Objects/clinic/dictobject.c.h index 3f06c0b5da..21c2b0b3d0 100644 --- a/Objects/clinic/dictobject.c.h +++ b/Objects/clinic/dictobject.c.h @@ -44,4 +44,72 @@ PyDoc_STRVAR(dict___contains____doc__, #define DICT___CONTAINS___METHODDEF \ {"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__}, -/*[clinic end generated code: output=69f3d767ed44e8ec input=a9049054013a1b77]*/ + +PyDoc_STRVAR(dict_get__doc__, +"get($self, key, default=None, /)\n" +"--\n" +"\n" +"D.get(key[, default]) -> D[key] if key in D, else default."); + +#define DICT_GET_METHODDEF \ + {"get", (PyCFunction)dict_get, METH_FASTCALL, dict_get__doc__}, + +static PyObject * +dict_get_impl(PyDictObject *self, PyObject *key, PyObject *failobj); + +static PyObject * +dict_get(PyDictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + PyObject *key; + PyObject *failobj = Py_None; + + if (!_PyArg_UnpackStack(args, nargs, "get", + 1, 2, + &key, &failobj)) { + goto exit; + } + + if (!_PyArg_NoStackKeywords("get", kwnames)) { + goto exit; + } + return_value = dict_get_impl(self, key, failobj); + +exit: + return return_value; +} + +PyDoc_STRVAR(dict_setdefault__doc__, +"setdefault($self, key, default=None, /)\n" +"--\n" +"\n" +"D.get(key,default), also set D[key]=default if key not in D."); + +#define DICT_SETDEFAULT_METHODDEF \ + {"setdefault", (PyCFunction)dict_setdefault, METH_FASTCALL, dict_setdefault__doc__}, + +static PyObject * +dict_setdefault_impl(PyDictObject *self, PyObject *key, PyObject *defaultobj); + +static PyObject * +dict_setdefault(PyDictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + PyObject *key; + PyObject *defaultobj = Py_None; + + if (!_PyArg_UnpackStack(args, nargs, "setdefault", + 1, 2, + &key, &defaultobj)) { + goto exit; + } + + if (!_PyArg_NoStackKeywords("setdefault", kwnames)) { + goto exit; + } + return_value = dict_setdefault_impl(self, key, defaultobj); + +exit: + return return_value; +} +/*[clinic end generated code: output=1b0cea84b4b6989e input=a9049054013a1b77]*/ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 9950f50896..1a6eedd738 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2787,25 +2787,31 @@ dict___contains__(PyDictObject *self, PyObject *key) Py_RETURN_TRUE; } +/*[clinic input] +dict.get + + key: object + default as failobj: object = None + / + +D.get(key[, default]) -> D[key] if key in D, else default. +[clinic start generated code]*/ + static PyObject * -dict_get(PyDictObject *mp, PyObject *args) +dict_get_impl(PyDictObject *self, PyObject *key, PyObject *failobj) +/*[clinic end generated code: output=c4a84a7ddbca9b7b input=7c976a78f258e915]*/ { - PyObject *key; - PyObject *failobj = Py_None; PyObject *val = NULL; Py_hash_t hash; Py_ssize_t ix; - if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &failobj)) - return NULL; - if (!PyUnicode_CheckExact(key) || (hash = ((PyASCIIObject *) key)->hash) == -1) { hash = PyObject_Hash(key); if (hash == -1) return NULL; } - ix = (mp->ma_keys->dk_lookup)(mp, key, hash, &val, NULL); + ix = (self->ma_keys->dk_lookup) (self, key, hash, &val, NULL); if (ix == DKIX_ERROR) return NULL; if (ix == DKIX_EMPTY || val == NULL) { @@ -2899,16 +2905,23 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) return value; } +/*[clinic input] +dict.setdefault + + key: object + default as defaultobj: object = None + / + +D.get(key,default), also set D[key]=default if key not in D. +[clinic start generated code]*/ + static PyObject * -dict_setdefault(PyDictObject *mp, PyObject *args) +dict_setdefault_impl(PyDictObject *self, PyObject *key, PyObject *defaultobj) +/*[clinic end generated code: output=692f85384b0b292e input=178f0c81d496d5cd]*/ { - PyObject *key, *val; - PyObject *defaultobj = Py_None; + PyObject *val; - if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &key, &defaultobj)) - return NULL; - - val = PyDict_SetDefault((PyObject *)mp, key, defaultobj); + val = PyDict_SetDefault((PyObject *)self, key, defaultobj); Py_XINCREF(val); return val; } @@ -3072,12 +3085,6 @@ PyDoc_STRVAR(getitem__doc__, "x.__getitem__(y) <==> x[y]"); PyDoc_STRVAR(sizeof__doc__, "D.__sizeof__() -> size of D in memory, in bytes"); -PyDoc_STRVAR(get__doc__, -"D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None."); - -PyDoc_STRVAR(setdefault_doc__, -"D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D"); - PyDoc_STRVAR(pop__doc__, "D.pop(k[,d]) -> v, remove specified key and return the corresponding value.\n\ If key is not found, d is returned if given, otherwise KeyError is raised"); @@ -3116,10 +3123,8 @@ static PyMethodDef mapp_methods[] = { getitem__doc__}, {"__sizeof__", (PyCFunction)dict_sizeof, METH_NOARGS, sizeof__doc__}, - {"get", (PyCFunction)dict_get, METH_VARARGS, - get__doc__}, - {"setdefault", (PyCFunction)dict_setdefault, METH_VARARGS, - setdefault_doc__}, + DICT_GET_METHODDEF + DICT_SETDEFAULT_METHODDEF {"pop", (PyCFunction)dict_pop, METH_VARARGS, pop__doc__}, {"popitem", (PyCFunction)dict_popitem, METH_NOARGS, -- cgit v1.2.1 From 1c9596159bb39c2767bddedaa0dea93a945e7d2e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 19 Jan 2017 12:45:06 +0100 Subject: Add a note explaining why dict_update() doesn't use METH_FASTCALL Issue #29312. --- Objects/dictobject.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'Objects') diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 1a6eedd738..f9414865ad 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2347,6 +2347,9 @@ dict_update_common(PyObject *self, PyObject *args, PyObject *kwds, return result; } +/* Note: dict.update() uses the METH_VARARGS|METH_KEYWORDS calling convention. + Using METH_FASTCALL would make dict.update(**dict2) calls slower, see the + issue #29312. */ static PyObject * dict_update(PyObject *self, PyObject *args, PyObject *kwds) { -- cgit v1.2.1 From 7509cc460d9ad8b2989a4206c83881f9276db42a Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 19 Jan 2017 18:48:17 +0200 Subject: Issue #20186: Converted builtins enumerate() and reversed() to Argument Clinic. Patch by Tal Einat. --- Objects/clinic/enumobject.c.h | 71 ++++++++++++++++++++++++++++++++++ Objects/enumobject.c | 89 ++++++++++++++++++++++++------------------- 2 files changed, 121 insertions(+), 39 deletions(-) create mode 100644 Objects/clinic/enumobject.c.h (limited to 'Objects') diff --git a/Objects/clinic/enumobject.c.h b/Objects/clinic/enumobject.c.h new file mode 100644 index 0000000000..0f05cf84cb --- /dev/null +++ b/Objects/clinic/enumobject.c.h @@ -0,0 +1,71 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(enum_new__doc__, +"enumerate(iterable, start=0)\n" +"--\n" +"\n" +"Return an enumerate object.\n" +"\n" +" iterable\n" +" an object supporting iteration\n" +"\n" +"The enumerate object yields pairs containing a count (from start, which\n" +"defaults to zero) and a value yielded by the iterable argument.\n" +"\n" +"enumerate is useful for obtaining an indexed list:\n" +" (0, seq[0]), (1, seq[1]), (2, seq[2]), ..."); + +static PyObject * +enum_new_impl(PyTypeObject *type, PyObject *iterable, PyObject *start); + +static PyObject * +enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"iterable", "start", NULL}; + static _PyArg_Parser _parser = {"O|O:enumerate", _keywords, 0}; + PyObject *iterable; + PyObject *start = 0; + + if (!_PyArg_ParseTupleAndKeywordsFast(args, kwargs, &_parser, + &iterable, &start)) { + goto exit; + } + return_value = enum_new_impl(type, iterable, start); + +exit: + return return_value; +} + +PyDoc_STRVAR(reversed_new__doc__, +"reversed(sequence, /)\n" +"--\n" +"\n" +"Return a reverse iterator over the values of the given sequence."); + +static PyObject * +reversed_new_impl(PyTypeObject *type, PyObject *seq); + +static PyObject * +reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *return_value = NULL; + PyObject *seq; + + if ((type == &PyReversed_Type) && + !_PyArg_NoKeywords("reversed", kwargs)) { + goto exit; + } + if (!PyArg_UnpackTuple(args, "reversed", + 1, 1, + &seq)) { + goto exit; + } + return_value = reversed_new_impl(type, seq); + +exit: + return return_value; +} +/*[clinic end generated code: output=9008c36999c57218 input=a9049054013a1b77]*/ diff --git a/Objects/enumobject.c b/Objects/enumobject.c index 72d31b16af..480768fbde 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -2,6 +2,14 @@ #include "Python.h" +#include "clinic/enumobject.c.h" + +/*[clinic input] +class enumerate "enumobject *" "&PyEnum_Type" +class reversed "reversedobject *" "&PyReversed_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=d2dfdf1a88c88975]*/ + typedef struct { PyObject_HEAD Py_ssize_t en_index; /* current index of enumeration */ @@ -10,17 +18,29 @@ typedef struct { PyObject* en_longindex; /* index for sequences >= PY_SSIZE_T_MAX */ } enumobject; + +/*[clinic input] +@classmethod +enumerate.__new__ as enum_new + + iterable: object + an object supporting iteration + start: object = 0 + +Return an enumerate object. + +The enumerate object yields pairs containing a count (from start, which +defaults to zero) and a value yielded by the iterable argument. + +enumerate is useful for obtaining an indexed list: + (0, seq[0]), (1, seq[1]), (2, seq[2]), ... +[clinic start generated code]*/ + static PyObject * -enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +enum_new_impl(PyTypeObject *type, PyObject *iterable, PyObject *start) +/*[clinic end generated code: output=e95e6e439f812c10 input=782e4911efcb8acf]*/ { enumobject *en; - PyObject *seq = NULL; - PyObject *start = NULL; - static char *kwlist[] = {"iterable", "start", 0}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:enumerate", kwlist, - &seq, &start)) - return NULL; en = (enumobject *)type->tp_alloc(type, 0); if (en == NULL) @@ -45,7 +65,7 @@ enum_new(PyTypeObject *type, PyObject *args, PyObject *kwds) en->en_index = 0; en->en_longindex = NULL; } - en->en_sit = PyObject_GetIter(seq); + en->en_sit = PyObject_GetIter(iterable); if (en->en_sit == NULL) { Py_DECREF(en); return NULL; @@ -174,15 +194,6 @@ static PyMethodDef enum_methods[] = { {NULL, NULL} /* sentinel */ }; -PyDoc_STRVAR(enum_doc, -"enumerate(iterable[, start]) -> iterator for index, value of iterable\n" -"\n" -"Return an enumerate object. iterable must be another object that supports\n" -"iteration. The enumerate object yields pairs containing a count (from\n" -"start, which defaults to zero) and a value yielded by the iterable argument.\n" -"enumerate is useful for obtaining an indexed list:\n" -" (0, seq[0]), (1, seq[1]), (2, seq[2]), ..."); - PyTypeObject PyEnum_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "enumerate", /* tp_name */ @@ -205,13 +216,13 @@ PyTypeObject PyEnum_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - enum_doc, /* tp_doc */ + Py_TPFLAGS_BASETYPE, /* tp_flags */ + enum_new__doc__, /* tp_doc */ (traverseproc)enum_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ + PyObject_SelfIter, /* tp_iter */ (iternextfunc)enum_next, /* tp_iternext */ enum_methods, /* tp_methods */ 0, /* tp_members */ @@ -235,20 +246,25 @@ typedef struct { PyObject* seq; } reversedobject; +/*[clinic input] +@classmethod +reversed.__new__ as reversed_new + + sequence as seq: object + / + +Return a reverse iterator over the values of the given sequence. +[clinic start generated code]*/ + static PyObject * -reversed_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +reversed_new_impl(PyTypeObject *type, PyObject *seq) +/*[clinic end generated code: output=f7854cc1df26f570 input=aeb720361e5e3f1d]*/ { Py_ssize_t n; - PyObject *seq, *reversed_meth; + PyObject *reversed_meth; reversedobject *ro; _Py_IDENTIFIER(__reversed__); - if (type == &PyReversed_Type && !_PyArg_NoKeywords("reversed()", kwds)) - return NULL; - - if (!PyArg_UnpackTuple(args, "reversed", 1, 1, &seq) ) - return NULL; - reversed_meth = _PyObject_LookupSpecial(seq, &PyId___reversed__); if (reversed_meth == Py_None) { Py_DECREF(reversed_meth); @@ -322,11 +338,6 @@ reversed_next(reversedobject *ro) return NULL; } -PyDoc_STRVAR(reversed_doc, -"reversed(sequence) -> reverse iterator over values of the sequence\n" -"\n" -"Return a reverse iterator"); - static PyObject * reversed_len(reversedobject *ro) { @@ -393,7 +404,7 @@ PyTypeObject PyReversed_Type = { 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ - 0, /* tp_as_sequence */ + 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ @@ -402,15 +413,15 @@ PyTypeObject PyReversed_Type = { 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | - Py_TPFLAGS_BASETYPE, /* tp_flags */ - reversed_doc, /* tp_doc */ + Py_TPFLAGS_BASETYPE, /* tp_flags */ + reversed_new__doc__, /* tp_doc */ (traverseproc)reversed_traverse,/* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ + PyObject_SelfIter, /* tp_iter */ (iternextfunc)reversed_next, /* tp_iternext */ - reversediter_methods, /* tp_methods */ + reversediter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ -- cgit v1.2.1 From ca1f7e8b325371854b2c8396cf3e9aae9f31b5e4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 19 Jan 2017 19:00:30 +0200 Subject: Issue #29311: Argument Clinic generates reasonable name for the parameter "default". --- Objects/clinic/dictobject.c.h | 19 ++++++++++--------- Objects/dictobject.c | 17 +++++++++-------- 2 files changed, 19 insertions(+), 17 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/dictobject.c.h b/Objects/clinic/dictobject.c.h index 21c2b0b3d0..deec4241ea 100644 --- a/Objects/clinic/dictobject.c.h +++ b/Objects/clinic/dictobject.c.h @@ -55,25 +55,25 @@ PyDoc_STRVAR(dict_get__doc__, {"get", (PyCFunction)dict_get, METH_FASTCALL, dict_get__doc__}, static PyObject * -dict_get_impl(PyDictObject *self, PyObject *key, PyObject *failobj); +dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value); static PyObject * dict_get(PyDictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *key; - PyObject *failobj = Py_None; + PyObject *default_value = Py_None; if (!_PyArg_UnpackStack(args, nargs, "get", 1, 2, - &key, &failobj)) { + &key, &default_value)) { goto exit; } if (!_PyArg_NoStackKeywords("get", kwnames)) { goto exit; } - return_value = dict_get_impl(self, key, failobj); + return_value = dict_get_impl(self, key, default_value); exit: return return_value; @@ -89,27 +89,28 @@ PyDoc_STRVAR(dict_setdefault__doc__, {"setdefault", (PyCFunction)dict_setdefault, METH_FASTCALL, dict_setdefault__doc__}, static PyObject * -dict_setdefault_impl(PyDictObject *self, PyObject *key, PyObject *defaultobj); +dict_setdefault_impl(PyDictObject *self, PyObject *key, + PyObject *default_value); static PyObject * dict_setdefault(PyDictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; PyObject *key; - PyObject *defaultobj = Py_None; + PyObject *default_value = Py_None; if (!_PyArg_UnpackStack(args, nargs, "setdefault", 1, 2, - &key, &defaultobj)) { + &key, &default_value)) { goto exit; } if (!_PyArg_NoStackKeywords("setdefault", kwnames)) { goto exit; } - return_value = dict_setdefault_impl(self, key, defaultobj); + return_value = dict_setdefault_impl(self, key, default_value); exit: return return_value; } -/*[clinic end generated code: output=1b0cea84b4b6989e input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6e9d917602373072 input=a9049054013a1b77]*/ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index f9414865ad..9ff52c32aa 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2794,15 +2794,15 @@ dict___contains__(PyDictObject *self, PyObject *key) dict.get key: object - default as failobj: object = None + default: object = None / D.get(key[, default]) -> D[key] if key in D, else default. [clinic start generated code]*/ static PyObject * -dict_get_impl(PyDictObject *self, PyObject *key, PyObject *failobj) -/*[clinic end generated code: output=c4a84a7ddbca9b7b input=7c976a78f258e915]*/ +dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value) +/*[clinic end generated code: output=bba707729dee05bf input=e73ab0f028f4b2be]*/ { PyObject *val = NULL; Py_hash_t hash; @@ -2818,7 +2818,7 @@ dict_get_impl(PyDictObject *self, PyObject *key, PyObject *failobj) if (ix == DKIX_ERROR) return NULL; if (ix == DKIX_EMPTY || val == NULL) { - val = failobj; + val = default_value; } Py_INCREF(val); return val; @@ -2912,19 +2912,20 @@ PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *defaultobj) dict.setdefault key: object - default as defaultobj: object = None + default: object = None / D.get(key,default), also set D[key]=default if key not in D. [clinic start generated code]*/ static PyObject * -dict_setdefault_impl(PyDictObject *self, PyObject *key, PyObject *defaultobj) -/*[clinic end generated code: output=692f85384b0b292e input=178f0c81d496d5cd]*/ +dict_setdefault_impl(PyDictObject *self, PyObject *key, + PyObject *default_value) +/*[clinic end generated code: output=f8c1101ebf69e220 input=b2826255bacd845a]*/ { PyObject *val; - val = PyDict_SetDefault((PyObject *)self, key, defaultobj); + val = PyDict_SetDefault((PyObject *)self, key, default_value); Py_XINCREF(val); return val; } -- cgit v1.2.1 From cece81f7dee3141bee23cc291834f4c04ebaf6c2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 19 Jan 2017 19:38:13 +0200 Subject: Issue #29289: Argument Clinic generates reasonable name for the parameter "default". --- Objects/clinic/odictobject.c.h | 10 +++++----- Objects/odictobject.c | 18 +++++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/odictobject.c.h b/Objects/clinic/odictobject.c.h index 5543f9463e..ee35af66b0 100644 --- a/Objects/clinic/odictobject.c.h +++ b/Objects/clinic/odictobject.c.h @@ -46,7 +46,7 @@ PyDoc_STRVAR(OrderedDict_setdefault__doc__, static PyObject * OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, - PyObject *failobj); + PyObject *default_value); static PyObject * OrderedDict_setdefault(PyODictObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) @@ -55,13 +55,13 @@ OrderedDict_setdefault(PyODictObject *self, PyObject **args, Py_ssize_t nargs, P static const char * const _keywords[] = {"key", "default", NULL}; static _PyArg_Parser _parser = {"O|O:setdefault", _keywords, 0}; PyObject *key; - PyObject *failobj = Py_None; + PyObject *default_value = Py_None; if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, - &key, &failobj)) { + &key, &default_value)) { goto exit; } - return_value = OrderedDict_setdefault_impl(self, key, failobj); + return_value = OrderedDict_setdefault_impl(self, key, default_value); exit: return return_value; @@ -132,4 +132,4 @@ OrderedDict_move_to_end(PyODictObject *self, PyObject **args, Py_ssize_t nargs, exit: return return_value; } -/*[clinic end generated code: output=f2641e1277045b59 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=84ef19e7b5db0086 input=a9049054013a1b77]*/ diff --git a/Objects/odictobject.c b/Objects/odictobject.c index aac454c817..8b1e114181 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -1012,15 +1012,15 @@ Done: OrderedDict.setdefault key: object - default as failobj: object = None + default: object = None od.get(k,d), also set od[k]=d if k not in od. [clinic start generated code]*/ static PyObject * OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, - PyObject *failobj) -/*[clinic end generated code: output=605d0f6f61ccb0a6 input=4ee5006f32f5691b]*/ + PyObject *default_value) +/*[clinic end generated code: output=97537cb7c28464b6 input=d5e940fcea7a5a67]*/ { PyObject *result = NULL; @@ -1030,9 +1030,9 @@ OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, if (PyErr_Occurred()) return NULL; assert(_odict_find_node(self, key) == NULL); - if (PyODict_SetItem((PyObject *)self, key, failobj) >= 0) { - result = failobj; - Py_INCREF(failobj); + if (PyODict_SetItem((PyObject *)self, key, default_value) >= 0) { + result = default_value; + Py_INCREF(result); } } else { @@ -1047,9 +1047,9 @@ OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, else if (exists) { result = PyObject_GetItem((PyObject *)self, key); } - else if (PyObject_SetItem((PyObject *)self, key, failobj) >= 0) { - result = failobj; - Py_INCREF(failobj); + else if (PyObject_SetItem((PyObject *)self, key, default_value) >= 0) { + result = default_value; + Py_INCREF(result); } } -- cgit v1.2.1 From 8f993e3ac6565928b14ffc0fcef23775f1b1e3f5 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 21 Jan 2017 23:05:00 +0200 Subject: Issue #29331: Simplified argument parsing in sorted() and list.sort(). --- Objects/listobject.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'Objects') diff --git a/Objects/listobject.c b/Objects/listobject.c index 05dddfc6d7..b21f637c56 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1912,7 +1912,7 @@ reverse_sortslice(sortslice *s, Py_ssize_t n) * duplicated). */ static PyObject * -listsort(PyListObject *self, PyObject *args, PyObject *kwds) +listsort_impl(PyListObject *self, PyObject *keyfunc, int reverse) { MergeState ms; Py_ssize_t nremaining; @@ -1922,24 +1922,11 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds) PyObject **saved_ob_item; PyObject **final_ob_item; PyObject *result = NULL; /* guilty until proved innocent */ - int reverse = 0; - PyObject *keyfunc = NULL; Py_ssize_t i; - static char *kwlist[] = {"key", "reverse", 0}; PyObject **keys; assert(self != NULL); assert (PyList_Check(self)); - if (args != NULL) { - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oi:sort", - kwlist, &keyfunc, &reverse)) - return NULL; - if (Py_SIZE(args) > 0) { - PyErr_SetString(PyExc_TypeError, - "must use keyword argument for key function"); - return NULL; - } - } if (keyfunc == Py_None) keyfunc = NULL; @@ -2088,6 +2075,19 @@ keyfunc_fail: #undef IFLT #undef ISLT +static PyObject * +listsort(PyListObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"key", "reverse", 0}; + PyObject *keyfunc = NULL; + int reverse = 0; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$Oi:sort", + kwlist, &keyfunc, &reverse)) + return NULL; + return listsort_impl(self, keyfunc, reverse); +} + int PyList_Sort(PyObject *v) { @@ -2095,7 +2095,7 @@ PyList_Sort(PyObject *v) PyErr_BadInternalCall(); return -1; } - v = listsort((PyListObject *)v, (PyObject *)NULL, (PyObject *)NULL); + v = listsort_impl((PyListObject *)v, NULL, 0); if (v == NULL) return -1; Py_DECREF(v); -- cgit v1.2.1 From 72ded8136b92c1b107f629021cf231fd3163f041 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sun, 22 Jan 2017 23:07:07 +0200 Subject: Issue #28769: The result of PyUnicode_AsUTF8AndSize() and PyUnicode_AsUTF8() is now of type "const char *" rather of "char *". --- Objects/object.c | 8 ++++---- Objects/unicodeobject.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'Objects') diff --git a/Objects/object.c b/Objects/object.c index 7b80bcb91d..93cdc1014f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -890,10 +890,10 @@ PyObject_GetAttr(PyObject *v, PyObject *name) if (tp->tp_getattro != NULL) return (*tp->tp_getattro)(v, name); if (tp->tp_getattr != NULL) { - char *name_str = PyUnicode_AsUTF8(name); + const char *name_str = PyUnicode_AsUTF8(name); if (name_str == NULL) return NULL; - return (*tp->tp_getattr)(v, name_str); + return (*tp->tp_getattr)(v, (char *)name_str); } PyErr_Format(PyExc_AttributeError, "'%.50s' object has no attribute '%U'", @@ -934,10 +934,10 @@ PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value) return err; } if (tp->tp_setattr != NULL) { - char *name_str = PyUnicode_AsUTF8(name); + const char *name_str = PyUnicode_AsUTF8(name); if (name_str == NULL) return -1; - err = (*tp->tp_setattr)(v, name_str, value); + err = (*tp->tp_setattr)(v, (char *)name_str, value); Py_DECREF(name); return err; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 5fbe56cce1..b711f0ccce 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3972,7 +3972,7 @@ PyUnicode_FSDecoder(PyObject* arg, void* addr) } -char* +const char * PyUnicode_AsUTF8AndSize(PyObject *unicode, Py_ssize_t *psize) { PyObject *bytes; @@ -4007,7 +4007,7 @@ PyUnicode_AsUTF8AndSize(PyObject *unicode, Py_ssize_t *psize) return PyUnicode_UTF8(unicode); } -char* +const char * PyUnicode_AsUTF8(PyObject *unicode) { return PyUnicode_AsUTF8AndSize(unicode, NULL); -- cgit v1.2.1 From bfeec6d871e3db2e0ddfdef01387913bc19cadd4 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 23 Jan 2017 09:47:21 +0200 Subject: Issue #28999: Use Py_RETURN_NONE, Py_RETURN_TRUE and Py_RETURN_FALSE wherever possible. Patch is writen with Coccinelle. --- Objects/descrobject.c | 6 ++---- Objects/exceptions.c | 6 ++---- Objects/fileobject.c | 3 +-- Objects/funcobject.c | 6 ++---- Objects/genobject.c | 3 +-- Objects/listobject.c | 6 ++---- Objects/tupleobject.c | 6 ++---- Objects/typeobject.c | 36 ++++++++++++------------------------ Objects/unicodeobject.c | 4 +--- 9 files changed, 25 insertions(+), 51 deletions(-) (limited to 'Objects') diff --git a/Objects/descrobject.c b/Objects/descrobject.c index a254a2a673..3fb34a3d7b 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -419,8 +419,7 @@ static PyObject * member_get_doc(PyMemberDescrObject *descr, void *closure) { if (descr->d_member->doc == NULL) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } return PyUnicode_FromString(descr->d_member->doc); } @@ -435,8 +434,7 @@ static PyObject * getset_get_doc(PyGetSetDescrObject *descr, void *closure) { if (descr->d_getset->doc == NULL) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } return PyUnicode_FromString(descr->d_getset->doc); } diff --git a/Objects/exceptions.c b/Objects/exceptions.c index 57a786c022..35a8b66e01 100644 --- a/Objects/exceptions.c +++ b/Objects/exceptions.c @@ -184,8 +184,7 @@ static PyObject * BaseException_get_args(PyBaseExceptionObject *self) { if (self->args == NULL) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } Py_INCREF(self->args); return self->args; @@ -210,8 +209,7 @@ static PyObject * BaseException_get_tb(PyBaseExceptionObject *self) { if (self->traceback == NULL) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } Py_INCREF(self->traceback); return self->traceback; diff --git a/Objects/fileobject.c b/Objects/fileobject.c index fcdb5fd0a4..3c3d46da51 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -456,8 +456,7 @@ static PyMethodDef stdprinter_methods[] = { static PyObject * get_closed(PyStdPrinter_Object *self, void *closure) { - Py_INCREF(Py_False); - return Py_False; + Py_RETURN_FALSE; } static PyObject * diff --git a/Objects/funcobject.c b/Objects/funcobject.c index a3af4b372a..8ac88b15df 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -322,8 +322,7 @@ static PyObject * func_get_defaults(PyFunctionObject *op) { if (op->func_defaults == NULL) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } Py_INCREF(op->func_defaults); return op->func_defaults; @@ -350,8 +349,7 @@ static PyObject * func_get_kwdefaults(PyFunctionObject *op) { if (op->func_kwdefaults == NULL) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } Py_INCREF(op->func_kwdefaults); return op->func_kwdefaults; diff --git a/Objects/genobject.c b/Objects/genobject.c index 59f53cefcb..24a1da6f3e 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -402,8 +402,7 @@ gen_close(PyGenObject *gen, PyObject *args) if (PyErr_ExceptionMatches(PyExc_StopIteration) || PyErr_ExceptionMatches(PyExc_GeneratorExit)) { PyErr_Clear(); /* ignore these errors */ - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } return NULL; } diff --git a/Objects/listobject.c b/Objects/listobject.c index b21f637c56..89941749d4 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -2284,12 +2284,10 @@ list_richcompare(PyObject *v, PyObject *w, int op) /* We have an item that differs -- shortcuts for EQ/NE */ if (op == Py_EQ) { - Py_INCREF(Py_False); - return Py_False; + Py_RETURN_FALSE; } if (op == Py_NE) { - Py_INCREF(Py_True); - return Py_True; + Py_RETURN_TRUE; } /* Compare the final item again using the proper operator */ diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index c0ff499e72..5bcadeb9f6 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -631,12 +631,10 @@ tuplerichcompare(PyObject *v, PyObject *w, int op) /* We have an item that differs -- shortcuts for EQ/NE */ if (op == Py_EQ) { - Py_INCREF(Py_False); - return Py_False; + Py_RETURN_FALSE; } if (op == Py_NE) { - Py_INCREF(Py_True); - return Py_True; + Py_RETURN_TRUE; } /* Compare the final item again using the proper operator */ diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 0fdff318b8..bf6d3f12c3 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -140,8 +140,7 @@ _PyType_GetDocFromInternalDoc(const char *name, const char *internal_doc) const char *doc = _PyType_DocWithoutSignature(name, internal_doc); if (!doc || *doc == '\0') { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } return PyUnicode_FromString(doc); @@ -158,8 +157,7 @@ _PyType_GetTextSignatureFromInternalDoc(const char *name, const char *internal_d else end = NULL; if (!end) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* back "end" up until it points just past the final ')' */ @@ -761,8 +759,7 @@ static PyObject * type_dict(PyTypeObject *type, void *context) { if (type->tp_dict == NULL) { - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } return PyDictProxy_New(type->tp_dict); } @@ -5330,8 +5327,7 @@ wrap_sq_setitem(PyObject *self, PyObject *args, void *wrapped) res = (*func)(self, i, value); if (res == -1 && PyErr_Occurred()) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject * @@ -5351,8 +5347,7 @@ wrap_sq_delitem(PyObject *self, PyObject *args, void *wrapped) res = (*func)(self, i, NULL); if (res == -1 && PyErr_Occurred()) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* XXX objobjproc is a misnomer; should be objargpred */ @@ -5385,8 +5380,7 @@ wrap_objobjargproc(PyObject *self, PyObject *args, void *wrapped) res = (*func)(self, key, value); if (res == -1 && PyErr_Occurred()) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject * @@ -5402,8 +5396,7 @@ wrap_delitem(PyObject *self, PyObject *args, void *wrapped) res = (*func)(self, key, NULL); if (res == -1 && PyErr_Occurred()) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } /* Helper to check for object.__setattr__ or __delattr__ applied to a type. @@ -5440,8 +5433,7 @@ wrap_setattr(PyObject *self, PyObject *args, void *wrapped) res = (*func)(self, name, value); if (res < 0) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject * @@ -5459,8 +5451,7 @@ wrap_delattr(PyObject *self, PyObject *args, void *wrapped) res = (*func)(self, name, NULL); if (res < 0) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject * @@ -5571,8 +5562,7 @@ wrap_descr_set(PyObject *self, PyObject *args, void *wrapped) ret = (*func)(self, obj, value); if (ret < 0) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject * @@ -5588,8 +5578,7 @@ wrap_descr_delete(PyObject *self, PyObject *args, void *wrapped) ret = (*func)(self, obj, NULL); if (ret < 0) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject * @@ -5599,8 +5588,7 @@ wrap_init(PyObject *self, PyObject *args, void *wrapped, PyObject *kwds) if (func(self, args, kwds) < 0) return NULL; - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } static PyObject * diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index b711f0ccce..0b79c5bd1a 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -8254,9 +8254,7 @@ charmapencode_lookup(Py_UCS4 c, PyObject *mapping) if (PyErr_ExceptionMatches(PyExc_LookupError)) { /* No mapping found means: mapping is undefined. */ PyErr_Clear(); - x = Py_None; - Py_INCREF(x); - return x; + Py_RETURN_NONE; } else return NULL; } -- cgit v1.2.1 From 1bd620bca594ba9193c63e79e7836765d23047cc Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 23 Jan 2017 10:23:58 +0200 Subject: Issue #28999: Use Py_RETURN_NONE, Py_RETURN_TRUE and Py_RETURN_FALSE wherever possible but Coccinelle couldn't find opportunity. --- Objects/stringlib/unicode_format.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'Objects') diff --git a/Objects/stringlib/unicode_format.h b/Objects/stringlib/unicode_format.h index 14fa28ea54..7ac0d75166 100644 --- a/Objects/stringlib/unicode_format.h +++ b/Objects/stringlib/unicode_format.h @@ -60,10 +60,8 @@ SubString_init(SubString *str, PyObject *s, Py_ssize_t start, Py_ssize_t end) Py_LOCAL_INLINE(PyObject *) SubString_new_object(SubString *str) { - if (str->str == NULL) { - Py_INCREF(Py_None); - return Py_None; - } + if (str->str == NULL) + Py_RETURN_NONE; return PyUnicode_Substring(str->str, str->start, str->end); } -- cgit v1.2.1 From 8882e556eef08ade01461b9f4ccfe2d82bdae694 Mon Sep 17 00:00:00 2001 From: Martin Panter Date: Tue, 24 Jan 2017 00:30:06 +0000 Subject: Fix grammar in doc string, RST markup --- Objects/clinic/unicodeobject.c.h | 4 ++-- Objects/unicodeobject.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/unicodeobject.c.h b/Objects/clinic/unicodeobject.c.h index c4bf3a433c..509405e527 100644 --- a/Objects/clinic/unicodeobject.c.h +++ b/Objects/clinic/unicodeobject.c.h @@ -406,7 +406,7 @@ PyDoc_STRVAR(unicode_join__doc__, "\n" "Concatenate any number of strings.\n" "\n" -"The string whose method is called is inserted in between each given strings.\n" +"The string whose method is called is inserted in between each given string.\n" "The result is returned as a new string.\n" "\n" "Example: \'.\'.join([\'ab\', \'pq\', \'rs\']) -> \'ab.pq.rs\'"); @@ -962,4 +962,4 @@ unicode_sizeof(PyObject *self, PyObject *Py_UNUSED(ignored)) { return unicode_sizeof_impl(self); } -/*[clinic end generated code: output=3d73f3dfd6ec7d83 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=88b06f61edd282f9 input=a9049054013a1b77]*/ diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 0b79c5bd1a..d3516fa45f 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -12201,7 +12201,7 @@ str.join as unicode_join Concatenate any number of strings. -The string whose method is called is inserted in between each given strings. +The string whose method is called is inserted in between each given string. The result is returned as a new string. Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs' @@ -12209,7 +12209,7 @@ Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs' static PyObject * unicode_join(PyObject *self, PyObject *iterable) -/*[clinic end generated code: output=6857e7cecfe7bf98 input=d8311e5ccbafbeb6]*/ +/*[clinic end generated code: output=6857e7cecfe7bf98 input=2f70422bfb8fa189]*/ { return PyUnicode_Join(self, iterable); } -- cgit v1.2.1 From df457ae79fffb23d438ddd780dd0fbbb60062299 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Tue, 24 Jan 2017 15:05:30 +0100 Subject: Issue #29360: _PyStack_AsDict() doesn't check kwnames Remove two assertions which can fail on legit code. Keyword arguments are checked later with better tests and raise a regular (TypeError) exception. --- Objects/abstract.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 58640323dc..1e394f865a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2413,8 +2413,7 @@ _PyStack_AsDict(PyObject **values, PyObject *kwnames) for (i = 0; i < nkwargs; i++) { PyObject *key = PyTuple_GET_ITEM(kwnames, i); PyObject *value = *values++; - assert(PyUnicode_CheckExact(key)); - assert(PyDict_GetItem(kwdict, key) == NULL); + /* If key already exists, replace it with the new value */ if (PyDict_SetItem(kwdict, key, value)) { Py_DECREF(kwdict); return NULL; -- cgit v1.2.1 From 35d2352df15a03d98bb7296a49fd16032b949bb3 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 25 Jan 2017 00:30:04 +0200 Subject: Issues #29311, #29289: Fixed and improved docstrings for dict and OrderedDict methods. --- Objects/clinic/dictobject.c.h | 12 +++++++----- Objects/clinic/odictobject.c.h | 17 ++++++++--------- Objects/dictobject.c | 18 ++++++++++-------- Objects/odictobject.c | 23 +++++++++++------------ 4 files changed, 36 insertions(+), 34 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/dictobject.c.h b/Objects/clinic/dictobject.c.h index deec4241ea..97918e82a7 100644 --- a/Objects/clinic/dictobject.c.h +++ b/Objects/clinic/dictobject.c.h @@ -6,7 +6,7 @@ PyDoc_STRVAR(dict_fromkeys__doc__, "fromkeys($type, iterable, value=None, /)\n" "--\n" "\n" -"Returns a new dict with keys from iterable and values equal to value."); +"Create a new dictionary with keys from iterable and values set to value."); #define DICT_FROMKEYS_METHODDEF \ {"fromkeys", (PyCFunction)dict_fromkeys, METH_FASTCALL|METH_CLASS, dict_fromkeys__doc__}, @@ -40,7 +40,7 @@ PyDoc_STRVAR(dict___contains____doc__, "__contains__($self, key, /)\n" "--\n" "\n" -"True if D has a key k, else False."); +"True if the dictionary has a specified key, else False."); #define DICT___CONTAINS___METHODDEF \ {"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__}, @@ -49,7 +49,7 @@ PyDoc_STRVAR(dict_get__doc__, "get($self, key, default=None, /)\n" "--\n" "\n" -"D.get(key[, default]) -> D[key] if key in D, else default."); +"Return the value for key if key is in the dictionary, else default."); #define DICT_GET_METHODDEF \ {"get", (PyCFunction)dict_get, METH_FASTCALL, dict_get__doc__}, @@ -83,7 +83,9 @@ PyDoc_STRVAR(dict_setdefault__doc__, "setdefault($self, key, default=None, /)\n" "--\n" "\n" -"D.get(key,default), also set D[key]=default if key not in D."); +"Insert key with a value of default if key is not in the dictionary.\n" +"\n" +"Return the value for key if key is in the dictionary, else default."); #define DICT_SETDEFAULT_METHODDEF \ {"setdefault", (PyCFunction)dict_setdefault, METH_FASTCALL, dict_setdefault__doc__}, @@ -113,4 +115,4 @@ dict_setdefault(PyDictObject *self, PyObject **args, Py_ssize_t nargs, PyObject exit: return return_value; } -/*[clinic end generated code: output=6e9d917602373072 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=91aa6a9f3c402b1b input=a9049054013a1b77]*/ diff --git a/Objects/clinic/odictobject.c.h b/Objects/clinic/odictobject.c.h index ee35af66b0..0e5092cf7a 100644 --- a/Objects/clinic/odictobject.c.h +++ b/Objects/clinic/odictobject.c.h @@ -6,9 +6,7 @@ PyDoc_STRVAR(OrderedDict_fromkeys__doc__, "fromkeys($type, /, iterable, value=None)\n" "--\n" "\n" -"New ordered dictionary with keys from S.\n" -"\n" -"If not specified, the value defaults to None."); +"Create a new ordered dictionary with keys from iterable and values set to value."); #define ORDEREDDICT_FROMKEYS_METHODDEF \ {"fromkeys", (PyCFunction)OrderedDict_fromkeys, METH_FASTCALL|METH_CLASS, OrderedDict_fromkeys__doc__}, @@ -39,7 +37,9 @@ PyDoc_STRVAR(OrderedDict_setdefault__doc__, "setdefault($self, /, key, default=None)\n" "--\n" "\n" -"od.get(k,d), also set od[k]=d if k not in od."); +"Insert key with a value of default if key is not in the dictionary.\n" +"\n" +"Return the value for key if key is in the dictionary, else default."); #define ORDEREDDICT_SETDEFAULT_METHODDEF \ {"setdefault", (PyCFunction)OrderedDict_setdefault, METH_FASTCALL, OrderedDict_setdefault__doc__}, @@ -71,7 +71,7 @@ PyDoc_STRVAR(OrderedDict_popitem__doc__, "popitem($self, /, last=True)\n" "--\n" "\n" -"Return (k, v) and remove a (key, value) pair.\n" +"Remove and return a (key, value) pair from the dictionary.\n" "\n" "Pairs are returned in LIFO order if last is true or FIFO order if false."); @@ -103,10 +103,9 @@ PyDoc_STRVAR(OrderedDict_move_to_end__doc__, "move_to_end($self, /, key, last=True)\n" "--\n" "\n" -"\"Move an existing element to the end (or beginning if last==False).\n" +"Move an existing element to the end (or beginning if last is false).\n" "\n" -" Raises KeyError if the element does not exist.\n" -" When last=True, acts like a fast version of self[key]=self.pop(key)."); +"Raise KeyError if the element does not exist."); #define ORDEREDDICT_MOVE_TO_END_METHODDEF \ {"move_to_end", (PyCFunction)OrderedDict_move_to_end, METH_FASTCALL, OrderedDict_move_to_end__doc__}, @@ -132,4 +131,4 @@ OrderedDict_move_to_end(PyODictObject *self, PyObject **args, Py_ssize_t nargs, exit: return return_value; } -/*[clinic end generated code: output=84ef19e7b5db0086 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=a19a24ac37b42e5e input=a9049054013a1b77]*/ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 9ff52c32aa..00fd58c81d 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2311,12 +2311,12 @@ dict.fromkeys value: object=None / -Returns a new dict with keys from iterable and values equal to value. +Create a new dictionary with keys from iterable and values set to value. [clinic start generated code]*/ static PyObject * dict_fromkeys_impl(PyTypeObject *type, PyObject *iterable, PyObject *value) -/*[clinic end generated code: output=8fb98e4b10384999 input=b85a667f9bf4669d]*/ +/*[clinic end generated code: output=8fb98e4b10384999 input=382ba4855d0f74c3]*/ { return _PyDict_FromKeys((PyObject *)type, iterable, value); } @@ -2764,12 +2764,12 @@ dict.__contains__ key: object / -True if D has a key k, else False. +True if the dictionary has the specified key, else False. [clinic start generated code]*/ static PyObject * dict___contains__(PyDictObject *self, PyObject *key) -/*[clinic end generated code: output=a3d03db709ed6e6b input=b852b2a19b51ab24]*/ +/*[clinic end generated code: output=a3d03db709ed6e6b input=f39613886bf975b7]*/ { register PyDictObject *mp = self; Py_hash_t hash; @@ -2797,12 +2797,12 @@ dict.get default: object = None / -D.get(key[, default]) -> D[key] if key in D, else default. +Return the value for key if key is in the dictionary, else default. [clinic start generated code]*/ static PyObject * dict_get_impl(PyDictObject *self, PyObject *key, PyObject *default_value) -/*[clinic end generated code: output=bba707729dee05bf input=e73ab0f028f4b2be]*/ +/*[clinic end generated code: output=bba707729dee05bf input=279ddb5790b6b107]*/ { PyObject *val = NULL; Py_hash_t hash; @@ -2915,13 +2915,15 @@ dict.setdefault default: object = None / -D.get(key,default), also set D[key]=default if key not in D. +Insert key with a value of default if key is not in the dictionary. + +Return the value for key if key is in the dictionary, else default. [clinic start generated code]*/ static PyObject * dict_setdefault_impl(PyDictObject *self, PyObject *key, PyObject *default_value) -/*[clinic end generated code: output=f8c1101ebf69e220 input=b2826255bacd845a]*/ +/*[clinic end generated code: output=f8c1101ebf69e220 input=0f063756e815fd9d]*/ { PyObject *val; diff --git a/Objects/odictobject.c b/Objects/odictobject.c index 8b1e114181..c2cef21b49 100644 --- a/Objects/odictobject.c +++ b/Objects/odictobject.c @@ -926,14 +926,12 @@ OrderedDict.fromkeys iterable as seq: object value: object = None -New ordered dictionary with keys from S. - -If not specified, the value defaults to None. +Create a new ordered dictionary with keys from iterable and values set to value. [clinic start generated code]*/ static PyObject * OrderedDict_fromkeys_impl(PyTypeObject *type, PyObject *seq, PyObject *value) -/*[clinic end generated code: output=c10390d452d78d6d input=33eefc496d5eee7b]*/ +/*[clinic end generated code: output=c10390d452d78d6d input=1a0476c229c597b3]*/ { return _PyDict_FromKeys((PyObject *)type, seq, value); } @@ -1014,13 +1012,15 @@ OrderedDict.setdefault key: object default: object = None -od.get(k,d), also set od[k]=d if k not in od. +Insert key with a value of default if key is not in the dictionary. + +Return the value for key if key is in the dictionary, else default. [clinic start generated code]*/ static PyObject * OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key, PyObject *default_value) -/*[clinic end generated code: output=97537cb7c28464b6 input=d5e940fcea7a5a67]*/ +/*[clinic end generated code: output=97537cb7c28464b6 input=38e098381c1efbc6]*/ { PyObject *result = NULL; @@ -1165,14 +1165,14 @@ OrderedDict.popitem last: bool = True -Return (k, v) and remove a (key, value) pair. +Remove and return a (key, value) pair from the dictionary. Pairs are returned in LIFO order if last is true or FIFO order if false. [clinic start generated code]*/ static PyObject * OrderedDict_popitem_impl(PyODictObject *self, int last) -/*[clinic end generated code: output=98e7d986690d49eb input=4937da2015939126]*/ +/*[clinic end generated code: output=98e7d986690d49eb input=d992ac5ee8305e1a]*/ { PyObject *key, *value, *item = NULL; _ODictNode *node; @@ -1324,15 +1324,14 @@ OrderedDict.move_to_end key: object last: bool = True -"Move an existing element to the end (or beginning if last==False). +Move an existing element to the end (or beginning if last is false). - Raises KeyError if the element does not exist. - When last=True, acts like a fast version of self[key]=self.pop(key). +Raise KeyError if the element does not exist. [clinic start generated code]*/ static PyObject * OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last) -/*[clinic end generated code: output=fafa4c5cc9b92f20 input=3b8283f7d0e15e43]*/ +/*[clinic end generated code: output=fafa4c5cc9b92f20 input=d6ceff7132a2fcd7]*/ { _ODictNode *node; -- cgit v1.2.1 From 47aa45aa2e4dba5e37f848ca3144a0c298e64e00 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 25 Jan 2017 23:33:27 +0100 Subject: Issue #29358: Add postcondition checks on types --- Objects/typeobject.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'Objects') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index bf6d3f12c3..8d22051486 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -121,6 +121,22 @@ skip_signature(const char *doc) return NULL; } +#ifdef Py_DEBUG +static int +_PyType_CheckConsistency(PyTypeObject *type) +{ + if (!(type->tp_flags & Py_TPFLAGS_READY)) { + /* don't check types before PyType_Ready() */ + return 1; + } + + assert(!(type->tp_flags & Py_TPFLAGS_READYING)); + assert(type->tp_mro != NULL && PyTuple_Check(type->tp_mro)); + assert(type->tp_dict != NULL); + return 1; +} +#endif + static const char * _PyType_DocWithoutSignature(const char *name, const char *internal_doc) { @@ -719,6 +735,7 @@ type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context) Py_DECREF(old_bases); Py_DECREF(old_base); + assert(_PyType_CheckConsistency(type)); return res; undo: @@ -752,6 +769,7 @@ type_set_bases(PyTypeObject *type, PyObject *new_bases, void *context) Py_DECREF(old_base); } + assert(_PyType_CheckConsistency(type)); return -1; } @@ -3034,6 +3052,7 @@ type_getattro(PyTypeObject *type, PyObject *name) static int type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) { + int res; if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { PyErr_Format( PyExc_TypeError, @@ -3043,7 +3062,9 @@ type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) } if (_PyObject_GenericSetAttrWithDict((PyObject *)type, name, value, NULL) < 0) return -1; - return update_slot(type, name); + res = update_slot(type, name); + assert(_PyType_CheckConsistency(type)); + return res; } extern void @@ -4851,7 +4872,7 @@ PyType_Ready(PyTypeObject *type) Py_ssize_t i, n; if (type->tp_flags & Py_TPFLAGS_READY) { - assert(type->tp_dict != NULL); + assert(_PyType_CheckConsistency(type)); return 0; } assert((type->tp_flags & Py_TPFLAGS_READYING) == 0); @@ -5045,9 +5066,9 @@ PyType_Ready(PyTypeObject *type) } /* All done -- set the ready flag */ - assert(type->tp_dict != NULL); type->tp_flags = (type->tp_flags & ~Py_TPFLAGS_READYING) | Py_TPFLAGS_READY; + assert(_PyType_CheckConsistency(type)); return 0; error: -- cgit v1.2.1 From db58e46a50818a49b606b66d404f4c272e84ba2e Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Sat, 28 Jan 2017 16:35:44 +0900 Subject: Issue #29383: reduce temporary interned unicode add_methods(), add_members(), and add_getset() used PyDict_SetItemString() to register descriptor to the type's dict. So descr_new() and PyDict_SetItemString() creates interned unicode from same C string. This patch takes interned unicode from descriptor, and use PyDict_SetItem() instead of PyDict_SetItemString(). python_startup_no_site: default: Median +- std dev: 12.7 ms +- 0.1 ms patched: Median +- std dev: 12.5 ms +- 0.1 ms --- Objects/typeobject.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'Objects') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 8d22051486..0193192102 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4539,6 +4539,7 @@ add_methods(PyTypeObject *type, PyMethodDef *meth) for (; meth->ml_name != NULL; meth++) { PyObject *descr; int err; + int isdescr = 1; if (PyDict_GetItemString(dict, meth->ml_name) && !(meth->ml_flags & METH_COEXIST)) continue; @@ -4555,6 +4556,7 @@ add_methods(PyTypeObject *type, PyMethodDef *meth) if (cfunc == NULL) return -1; descr = PyStaticMethod_New(cfunc); + isdescr = 0; // PyStaticMethod is not PyDescrObject Py_DECREF(cfunc); } else { @@ -4562,7 +4564,12 @@ add_methods(PyTypeObject *type, PyMethodDef *meth) } if (descr == NULL) return -1; - err = PyDict_SetItemString(dict, meth->ml_name, descr); + if (isdescr) { + err = PyDict_SetItem(dict, PyDescr_NAME(descr), descr); + } + else { + err = PyDict_SetItemString(dict, meth->ml_name, descr); + } Py_DECREF(descr); if (err < 0) return -1; @@ -4582,7 +4589,7 @@ add_members(PyTypeObject *type, PyMemberDef *memb) descr = PyDescr_NewMember(type, memb); if (descr == NULL) return -1; - if (PyDict_SetItemString(dict, memb->name, descr) < 0) { + if (PyDict_SetItem(dict, PyDescr_NAME(descr), descr) < 0) { Py_DECREF(descr); return -1; } @@ -4604,7 +4611,7 @@ add_getset(PyTypeObject *type, PyGetSetDef *gsp) if (descr == NULL) return -1; - if (PyDict_SetItemString(dict, gsp->name, descr) < 0) { + if (PyDict_SetItem(dict, PyDescr_NAME(descr), descr) < 0) { Py_DECREF(descr); return -1; } -- cgit v1.2.1 From 62992ef31b28b380da92b990a53e2105a4612309 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 1 Feb 2017 23:12:20 +0200 Subject: Issue #20185: Converted the int class to Argument Clinic. Based on patch by Vajrasky Kok. --- Objects/clinic/longobject.c.h | 192 +++++++++++++++++++++++++++++++++ Objects/longobject.c | 246 +++++++++++++++++++----------------------- 2 files changed, 303 insertions(+), 135 deletions(-) create mode 100644 Objects/clinic/longobject.c.h (limited to 'Objects') diff --git a/Objects/clinic/longobject.c.h b/Objects/clinic/longobject.c.h new file mode 100644 index 0000000000..6a7b7debd2 --- /dev/null +++ b/Objects/clinic/longobject.c.h @@ -0,0 +1,192 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +PyDoc_STRVAR(int___getnewargs____doc__, +"__getnewargs__($self, /)\n" +"--\n" +"\n"); + +#define INT___GETNEWARGS___METHODDEF \ + {"__getnewargs__", (PyCFunction)int___getnewargs__, METH_NOARGS, int___getnewargs____doc__}, + +static PyObject * +int___getnewargs___impl(PyObject *self); + +static PyObject * +int___getnewargs__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return int___getnewargs___impl(self); +} + +PyDoc_STRVAR(int___format____doc__, +"__format__($self, format_spec, /)\n" +"--\n" +"\n"); + +#define INT___FORMAT___METHODDEF \ + {"__format__", (PyCFunction)int___format__, METH_O, int___format____doc__}, + +static PyObject * +int___format___impl(PyObject *self, PyObject *format_spec); + +static PyObject * +int___format__(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + PyObject *format_spec; + + if (!PyArg_Parse(arg, "U:__format__", &format_spec)) { + goto exit; + } + return_value = int___format___impl(self, format_spec); + +exit: + return return_value; +} + +PyDoc_STRVAR(int___sizeof____doc__, +"__sizeof__($self, /)\n" +"--\n" +"\n" +"Returns size in memory, in bytes."); + +#define INT___SIZEOF___METHODDEF \ + {"__sizeof__", (PyCFunction)int___sizeof__, METH_NOARGS, int___sizeof____doc__}, + +static Py_ssize_t +int___sizeof___impl(PyObject *self); + +static PyObject * +int___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + Py_ssize_t _return_value; + + _return_value = int___sizeof___impl(self); + if ((_return_value == -1) && PyErr_Occurred()) { + goto exit; + } + return_value = PyLong_FromSsize_t(_return_value); + +exit: + return return_value; +} + +PyDoc_STRVAR(int_bit_length__doc__, +"bit_length($self, /)\n" +"--\n" +"\n" +"Number of bits necessary to represent self in binary.\n" +"\n" +">>> bin(37)\n" +"\'0b100101\'\n" +">>> (37).bit_length()\n" +"6"); + +#define INT_BIT_LENGTH_METHODDEF \ + {"bit_length", (PyCFunction)int_bit_length, METH_NOARGS, int_bit_length__doc__}, + +static PyObject * +int_bit_length_impl(PyObject *self); + +static PyObject * +int_bit_length(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return int_bit_length_impl(self); +} + +PyDoc_STRVAR(int_to_bytes__doc__, +"to_bytes($self, /, length, byteorder, *, signed=False)\n" +"--\n" +"\n" +"Return an array of bytes representing an integer.\n" +"\n" +" length\n" +" Length of bytes object to use. An OverflowError is raised if the\n" +" integer is not representable with the given number of bytes.\n" +" byteorder\n" +" The byte order used to represent the integer. If byteorder is \'big\',\n" +" the most significant byte is at the beginning of the byte array. If\n" +" byteorder is \'little\', the most significant byte is at the end of the\n" +" byte array. To request the native byte order of the host system, use\n" +" `sys.byteorder\' as the byte order value.\n" +" signed\n" +" Determines whether two\'s complement is used to represent the integer.\n" +" If signed is False and a negative integer is given, an OverflowError\n" +" is raised."); + +#define INT_TO_BYTES_METHODDEF \ + {"to_bytes", (PyCFunction)int_to_bytes, METH_FASTCALL, int_to_bytes__doc__}, + +static PyObject * +int_to_bytes_impl(PyObject *self, Py_ssize_t length, PyObject *byteorder, + int is_signed); + +static PyObject * +int_to_bytes(PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"length", "byteorder", "signed", NULL}; + static _PyArg_Parser _parser = {"nU|$p:to_bytes", _keywords, 0}; + Py_ssize_t length; + PyObject *byteorder; + int is_signed = 0; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &length, &byteorder, &is_signed)) { + goto exit; + } + return_value = int_to_bytes_impl(self, length, byteorder, is_signed); + +exit: + return return_value; +} + +PyDoc_STRVAR(int_from_bytes__doc__, +"from_bytes($type, /, bytes, byteorder, *, signed=False)\n" +"--\n" +"\n" +"Return the integer represented by the given array of bytes.\n" +"\n" +" bytes\n" +" Holds the array of bytes to convert. The argument must either\n" +" support the buffer protocol or be an iterable object producing bytes.\n" +" Bytes and bytearray are examples of built-in objects that support the\n" +" buffer protocol.\n" +" byteorder\n" +" The byte order used to represent the integer. If byteorder is \'big\',\n" +" the most significant byte is at the beginning of the byte array. If\n" +" byteorder is \'little\', the most significant byte is at the end of the\n" +" byte array. To request the native byte order of the host system, use\n" +" `sys.byteorder\' as the byte order value.\n" +" signed\n" +" Indicates whether two\'s complement is used to represent the integer."); + +#define INT_FROM_BYTES_METHODDEF \ + {"from_bytes", (PyCFunction)int_from_bytes, METH_FASTCALL|METH_CLASS, int_from_bytes__doc__}, + +static PyObject * +int_from_bytes_impl(PyTypeObject *type, PyObject *bytes_obj, + PyObject *byteorder, int is_signed); + +static PyObject * +int_from_bytes(PyTypeObject *type, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *return_value = NULL; + static const char * const _keywords[] = {"bytes", "byteorder", "signed", NULL}; + static _PyArg_Parser _parser = {"OU|$p:from_bytes", _keywords, 0}; + PyObject *bytes_obj; + PyObject *byteorder; + int is_signed = 0; + + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &bytes_obj, &byteorder, &is_signed)) { + goto exit; + } + return_value = int_from_bytes_impl(type, bytes_obj, byteorder, is_signed); + +exit: + return return_value; +} +/*[clinic end generated code: output=a9bae2fd016e7b85 input=a9049054013a1b77]*/ diff --git a/Objects/longobject.c b/Objects/longobject.c index c95f9467ad..f37fbd7222 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -9,6 +9,12 @@ #include #include +#include "clinic/longobject.c.h" +/*[clinic input] +class int "PyObject *" "&PyLong_Type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=ec0275e3422a36e3]*/ + #ifndef NSMALLPOSINTS #define NSMALLPOSINTS 257 #endif @@ -4863,10 +4869,15 @@ long_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject *)newobj; } +/*[clinic input] +int.__getnewargs__ +[clinic start generated code]*/ + static PyObject * -long_getnewargs(PyLongObject *v) +int___getnewargs___impl(PyObject *self) +/*[clinic end generated code: output=839a49de3f00b61b input=5904770ab1fb8c75]*/ { - return Py_BuildValue("(N)", _PyLong_Copy(v)); + return Py_BuildValue("(N)", _PyLong_Copy((PyLongObject *)self)); } static PyObject * @@ -4879,16 +4890,20 @@ long_get1(PyLongObject *v, void *context) { return PyLong_FromLong(1L); } +/*[clinic input] +int.__format__ + + format_spec: unicode + / +[clinic start generated code]*/ + static PyObject * -long__format__(PyObject *self, PyObject *args) +int___format___impl(PyObject *self, PyObject *format_spec) +/*[clinic end generated code: output=b4929dee9ae18689 input=e31944a9b3e428b7]*/ { - PyObject *format_spec; _PyUnicodeWriter writer; int ret; - if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) - return NULL; - _PyUnicodeWriter_Init(&writer); ret = _PyLong_FormatAdvancedWriter( &writer, @@ -5066,31 +5081,50 @@ long_round(PyObject *self, PyObject *args) return result; } -static PyObject * -long_sizeof(PyLongObject *v) +/*[clinic input] +int.__sizeof__ -> Py_ssize_t + +Returns size in memory, in bytes. +[clinic start generated code]*/ + +static Py_ssize_t +int___sizeof___impl(PyObject *self) +/*[clinic end generated code: output=3303f008eaa6a0a5 input=9b51620c76fc4507]*/ { Py_ssize_t res; - res = offsetof(PyLongObject, ob_digit) + Py_ABS(Py_SIZE(v))*sizeof(digit); - return PyLong_FromSsize_t(res); + res = offsetof(PyLongObject, ob_digit) + Py_ABS(Py_SIZE(self))*sizeof(digit); + return res; } +/*[clinic input] +int.bit_length + +Number of bits necessary to represent self in binary. + +>>> bin(37) +'0b100101' +>>> (37).bit_length() +6 +[clinic start generated code]*/ + static PyObject * -long_bit_length(PyLongObject *v) +int_bit_length_impl(PyObject *self) +/*[clinic end generated code: output=fc1977c9353d6a59 input=e4eb7a587e849a32]*/ { PyLongObject *result, *x, *y; Py_ssize_t ndigits; int msd_bits; digit msd; - assert(v != NULL); - assert(PyLong_Check(v)); + assert(self != NULL); + assert(PyLong_Check(self)); - ndigits = Py_ABS(Py_SIZE(v)); + ndigits = Py_ABS(Py_SIZE(self)); if (ndigits == 0) return PyLong_FromLong(0); - msd = v->ob_digit[ndigits-1]; + msd = ((PyLongObject *)self)->ob_digit[ndigits-1]; msd_bits = bits_in_digit(msd); if (ndigits <= PY_SSIZE_T_MAX/PyLong_SHIFT) @@ -5127,15 +5161,6 @@ long_bit_length(PyLongObject *v) return NULL; } -PyDoc_STRVAR(long_bit_length_doc, -"int.bit_length() -> int\n\ -\n\ -Number of bits necessary to represent self in binary.\n\ ->>> bin(37)\n\ -'0b100101'\n\ ->>> (37).bit_length()\n\ -6"); - #if 0 static PyObject * long_is_finite(PyObject *v) @@ -5144,32 +5169,38 @@ long_is_finite(PyObject *v) } #endif +/*[clinic input] +int.to_bytes + + length: Py_ssize_t + Length of bytes object to use. An OverflowError is raised if the + integer is not representable with the given number of bytes. + byteorder: unicode + The byte order used to represent the integer. If byteorder is 'big', + the most significant byte is at the beginning of the byte array. If + byteorder is 'little', the most significant byte is at the end of the + byte array. To request the native byte order of the host system, use + `sys.byteorder' as the byte order value. + * + signed as is_signed: bool = False + Determines whether two's complement is used to represent the integer. + If signed is False and a negative integer is given, an OverflowError + is raised. + +Return an array of bytes representing an integer. +[clinic start generated code]*/ static PyObject * -long_to_bytes(PyLongObject *v, PyObject *args, PyObject *kwds) +int_to_bytes_impl(PyObject *self, Py_ssize_t length, PyObject *byteorder, + int is_signed) +/*[clinic end generated code: output=89c801df114050a3 input=ddac63f4c7bf414c]*/ { - PyObject *byteorder_str; - PyObject *is_signed_obj = NULL; - Py_ssize_t length; int little_endian; - int is_signed; PyObject *bytes; - static char *kwlist[] = {"length", "byteorder", "signed", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "nU|O:to_bytes", kwlist, - &length, &byteorder_str, - &is_signed_obj)) - return NULL; - - if (args != NULL && Py_SIZE(args) > 2) { - PyErr_SetString(PyExc_TypeError, - "'signed' is a keyword-only argument"); - return NULL; - } - if (_PyUnicode_EqualToASCIIString(byteorder_str, "little")) + if (_PyUnicode_EqualToASCIIString(byteorder, "little")) little_endian = 1; - else if (_PyUnicode_EqualToASCIIString(byteorder_str, "big")) + else if (_PyUnicode_EqualToASCIIString(byteorder, "big")) little_endian = 0; else { PyErr_SetString(PyExc_ValueError, @@ -5177,18 +5208,6 @@ long_to_bytes(PyLongObject *v, PyObject *args, PyObject *kwds) return NULL; } - if (is_signed_obj != NULL) { - int cmp = PyObject_IsTrue(is_signed_obj); - if (cmp < 0) - return NULL; - is_signed = cmp ? 1 : 0; - } - else { - /* If the signed argument was omitted, use False as the - default. */ - is_signed = 0; - } - if (length < 0) { PyErr_SetString(PyExc_ValueError, "length argument must be non-negative"); @@ -5199,7 +5218,8 @@ long_to_bytes(PyLongObject *v, PyObject *args, PyObject *kwds) if (bytes == NULL) return NULL; - if (_PyLong_AsByteArray(v, (unsigned char *)PyBytes_AS_STRING(bytes), + if (_PyLong_AsByteArray((PyLongObject *)self, + (unsigned char *)PyBytes_AS_STRING(bytes), length, little_endian, is_signed) < 0) { Py_DECREF(bytes); return NULL; @@ -5208,51 +5228,39 @@ long_to_bytes(PyLongObject *v, PyObject *args, PyObject *kwds) return bytes; } -PyDoc_STRVAR(long_to_bytes_doc, -"int.to_bytes(length, byteorder, *, signed=False) -> bytes\n\ -\n\ -Return an array of bytes representing an integer.\n\ -\n\ -The integer is represented using length bytes. An OverflowError is\n\ -raised if the integer is not representable with the given number of\n\ -bytes.\n\ -\n\ -The byteorder argument determines the byte order used to represent the\n\ -integer. If byteorder is 'big', the most significant byte is at the\n\ -beginning of the byte array. If byteorder is 'little', the most\n\ -significant byte is at the end of the byte array. To request the native\n\ -byte order of the host system, use `sys.byteorder' as the byte order value.\n\ -\n\ -The signed keyword-only argument determines whether two's complement is\n\ -used to represent the integer. If signed is False and a negative integer\n\ -is given, an OverflowError is raised."); +/*[clinic input] +@classmethod +int.from_bytes + + bytes as bytes_obj: object + Holds the array of bytes to convert. The argument must either + support the buffer protocol or be an iterable object producing bytes. + Bytes and bytearray are examples of built-in objects that support the + buffer protocol. + byteorder: unicode + The byte order used to represent the integer. If byteorder is 'big', + the most significant byte is at the beginning of the byte array. If + byteorder is 'little', the most significant byte is at the end of the + byte array. To request the native byte order of the host system, use + `sys.byteorder' as the byte order value. + * + signed as is_signed: bool = False + Indicates whether two's complement is used to represent the integer. + +Return the integer represented by the given array of bytes. +[clinic start generated code]*/ static PyObject * -long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds) +int_from_bytes_impl(PyTypeObject *type, PyObject *bytes_obj, + PyObject *byteorder, int is_signed) +/*[clinic end generated code: output=efc5d68e31f9314f input=cdf98332b6a821b0]*/ { - PyObject *byteorder_str; - PyObject *is_signed_obj = NULL; int little_endian; - int is_signed; - PyObject *obj; - PyObject *bytes; - PyObject *long_obj; - static char *kwlist[] = {"bytes", "byteorder", "signed", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OU|O:from_bytes", kwlist, - &obj, &byteorder_str, - &is_signed_obj)) - return NULL; + PyObject *long_obj, *bytes; - if (args != NULL && Py_SIZE(args) > 2) { - PyErr_SetString(PyExc_TypeError, - "'signed' is a keyword-only argument"); - return NULL; - } - - if (_PyUnicode_EqualToASCIIString(byteorder_str, "little")) + if (_PyUnicode_EqualToASCIIString(byteorder, "little")) little_endian = 1; - else if (_PyUnicode_EqualToASCIIString(byteorder_str, "big")) + else if (_PyUnicode_EqualToASCIIString(byteorder, "big")) little_endian = 0; else { PyErr_SetString(PyExc_ValueError, @@ -5260,19 +5268,7 @@ long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } - if (is_signed_obj != NULL) { - int cmp = PyObject_IsTrue(is_signed_obj); - if (cmp < 0) - return NULL; - is_signed = cmp ? 1 : 0; - } - else { - /* If the signed argument was omitted, use False as the - default. */ - is_signed = 0; - } - - bytes = PyObject_Bytes(obj); + bytes = PyObject_Bytes(bytes_obj); if (bytes == NULL) return NULL; @@ -5289,35 +5285,16 @@ long_from_bytes(PyTypeObject *type, PyObject *args, PyObject *kwds) return long_obj; } -PyDoc_STRVAR(long_from_bytes_doc, -"int.from_bytes(bytes, byteorder, *, signed=False) -> int\n\ -\n\ -Return the integer represented by the given array of bytes.\n\ -\n\ -The bytes argument must be a bytes-like object (e.g. bytes or bytearray).\n\ -\n\ -The byteorder argument determines the byte order used to represent the\n\ -integer. If byteorder is 'big', the most significant byte is at the\n\ -beginning of the byte array. If byteorder is 'little', the most\n\ -significant byte is at the end of the byte array. To request the native\n\ -byte order of the host system, use `sys.byteorder' as the byte order value.\n\ -\n\ -The signed keyword-only argument indicates whether two's complement is\n\ -used to represent the integer."); - static PyMethodDef long_methods[] = { {"conjugate", (PyCFunction)long_long, METH_NOARGS, "Returns self, the complex conjugate of any int."}, - {"bit_length", (PyCFunction)long_bit_length, METH_NOARGS, - long_bit_length_doc}, + INT_BIT_LENGTH_METHODDEF #if 0 {"is_finite", (PyCFunction)long_is_finite, METH_NOARGS, "Returns always True."}, #endif - {"to_bytes", (PyCFunction)long_to_bytes, - METH_VARARGS|METH_KEYWORDS, long_to_bytes_doc}, - {"from_bytes", (PyCFunction)long_from_bytes, - METH_VARARGS|METH_KEYWORDS|METH_CLASS, long_from_bytes_doc}, + INT_TO_BYTES_METHODDEF + INT_FROM_BYTES_METHODDEF {"__trunc__", (PyCFunction)long_long, METH_NOARGS, "Truncating an Integral returns itself."}, {"__floor__", (PyCFunction)long_long, METH_NOARGS, @@ -5327,10 +5304,9 @@ static PyMethodDef long_methods[] = { {"__round__", (PyCFunction)long_round, METH_VARARGS, "Rounding an Integral returns itself.\n" "Rounding with an ndigits argument also returns an integer."}, - {"__getnewargs__", (PyCFunction)long_getnewargs, METH_NOARGS}, - {"__format__", (PyCFunction)long__format__, METH_VARARGS}, - {"__sizeof__", (PyCFunction)long_sizeof, METH_NOARGS, - "Returns size in memory, in bytes"}, + INT___GETNEWARGS___METHODDEF + INT___FORMAT___METHODDEF + INT___SIZEOF___METHODDEF {NULL, NULL} /* sentinel */ }; -- cgit v1.2.1 From 4f4c038c0cd2a312cf9155e75f1be041b5085edd Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Thu, 2 Feb 2017 16:54:45 +0200 Subject: Issue #29421: Make int.to_bytes() and int.from_bytes() slightly faster (10-20% for small integers). --- Objects/longobject.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'Objects') diff --git a/Objects/longobject.c b/Objects/longobject.c index f37fbd7222..0bf6cee6c1 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -22,6 +22,9 @@ class int "PyObject *" "&PyLong_Type" #define NSMALLNEGINTS 5 #endif +_Py_IDENTIFIER(little); +_Py_IDENTIFIER(big); + /* convert a PyLong of size 1, 0 or -1 to an sdigit */ #define MEDIUM_VALUE(x) (assert(-1 <= Py_SIZE(x) && Py_SIZE(x) <= 1), \ Py_SIZE(x) < 0 ? -(sdigit)(x)->ob_digit[0] : \ @@ -5198,9 +5201,9 @@ int_to_bytes_impl(PyObject *self, Py_ssize_t length, PyObject *byteorder, int little_endian; PyObject *bytes; - if (_PyUnicode_EqualToASCIIString(byteorder, "little")) + if (_PyUnicode_EqualToASCIIId(byteorder, &PyId_little)) little_endian = 1; - else if (_PyUnicode_EqualToASCIIString(byteorder, "big")) + else if (_PyUnicode_EqualToASCIIId(byteorder, &PyId_big)) little_endian = 0; else { PyErr_SetString(PyExc_ValueError, @@ -5258,9 +5261,9 @@ int_from_bytes_impl(PyTypeObject *type, PyObject *bytes_obj, int little_endian; PyObject *long_obj, *bytes; - if (_PyUnicode_EqualToASCIIString(byteorder, "little")) + if (_PyUnicode_EqualToASCIIId(byteorder, &PyId_little)) little_endian = 1; - else if (_PyUnicode_EqualToASCIIString(byteorder, "big")) + else if (_PyUnicode_EqualToASCIIId(byteorder, &PyId_big)) little_endian = 0; else { PyErr_SetString(PyExc_ValueError, -- cgit v1.2.1 From 14593e19e199dd34f268b35987ddb288bf022039 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Thu, 2 Feb 2017 08:24:48 -0800 Subject: Remove unnecessary variables. * so->used never gets changed during a resize * so->filled only changes when dummies are present and being eliminated --- Objects/setobject.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'Objects') diff --git a/Objects/setobject.c b/Objects/setobject.c index 59ed7955e6..c72c0fae62 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -296,8 +296,6 @@ set_table_resize(PySetObject *so, Py_ssize_t minused) { Py_ssize_t newsize; setentry *oldtable, *newtable, *entry; - Py_ssize_t oldfill = so->fill; - Py_ssize_t oldused = so->used; Py_ssize_t oldmask = so->mask; size_t newmask; int is_oldtable_malloced; @@ -352,21 +350,20 @@ set_table_resize(PySetObject *so, Py_ssize_t minused) /* Make the set empty, using the new table. */ assert(newtable != oldtable); memset(newtable, 0, sizeof(setentry) * newsize); - so->fill = oldused; - so->used = oldused; so->mask = newsize - 1; so->table = newtable; /* Copy the data over; this is refcount-neutral for active entries; dummy entries aren't copied over, of course */ newmask = (size_t)so->mask; - if (oldfill == oldused) { + if (so->fill == so->used) { for (entry = oldtable; entry <= oldtable + oldmask; entry++) { if (entry->key != NULL) { set_insert_clean(newtable, newmask, entry->key, entry->hash); } } } else { + so->fill = so->used; for (entry = oldtable; entry <= oldtable + oldmask; entry++) { if (entry->key != NULL && entry->key != dummy) { set_insert_clean(newtable, newmask, entry->key, entry->hash); -- cgit v1.2.1 From 99c092a531abf57a8f5c37356dc6971cdfed497a Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Fri, 3 Feb 2017 07:43:03 +0900 Subject: Issue #29263: LOAD_METHOD support for C methods Calling builtin method is at most 10% faster. --- Objects/descrobject.c | 38 ++++++++++++++++++++++++++++++++++++ Objects/methodobject.c | 53 ++++++++++++++++++++++++++++---------------------- Objects/object.c | 4 ++-- 3 files changed, 70 insertions(+), 25 deletions(-) (limited to 'Objects') diff --git a/Objects/descrobject.c b/Objects/descrobject.c index 3fb34a3d7b..20c0d36eca 100644 --- a/Objects/descrobject.c +++ b/Objects/descrobject.c @@ -246,6 +246,44 @@ methoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwargs) return result; } +// same to methoddescr_call(), but use FASTCALL convention. +PyObject * +_PyMethodDescr_FastCallKeywords(PyObject *descrobj, + PyObject **args, Py_ssize_t nargs, + PyObject *kwnames) +{ + assert(Py_TYPE(descrobj) == &PyMethodDescr_Type); + PyMethodDescrObject *descr = (PyMethodDescrObject *)descrobj; + PyObject *self, *result; + + /* Make sure that the first argument is acceptable as 'self' */ + if (nargs < 1) { + PyErr_Format(PyExc_TypeError, + "descriptor '%V' of '%.100s' " + "object needs an argument", + descr_name((PyDescrObject *)descr), "?", + PyDescr_TYPE(descr)->tp_name); + return NULL; + } + self = args[0]; + if (!_PyObject_RealIsSubclass((PyObject *)Py_TYPE(self), + (PyObject *)PyDescr_TYPE(descr))) { + PyErr_Format(PyExc_TypeError, + "descriptor '%V' " + "requires a '%.100s' object " + "but received a '%.100s'", + descr_name((PyDescrObject *)descr), "?", + PyDescr_TYPE(descr)->tp_name, + self->ob_type->tp_name); + return NULL; + } + + result = _PyMethodDef_RawFastCallKeywords(descr->d_method, self, + args+1, nargs-1, kwnames); + result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL); + return result; +} + static PyObject * classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args, PyObject *kwds) diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 35a827e164..6618d78968 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -215,32 +215,24 @@ _PyCFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs, } PyObject * -_PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, - Py_ssize_t nargs, PyObject *kwnames) +_PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject **args, + Py_ssize_t nargs, PyObject *kwnames) { - PyCFunctionObject *func; - PyCFunction meth; - PyObject *self, *result; - Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); - int flags; + /* _PyMethodDef_RawFastCallKeywords() must not be called with an exception set, + because it can clear it (directly or indirectly) and so the + caller loses its exception */ + assert(!PyErr_Occurred()); - assert(func_obj != NULL); - assert(PyCFunction_Check(func_obj)); + assert(method != NULL); assert(nargs >= 0); assert(kwnames == NULL || PyTuple_CheckExact(kwnames)); - assert((nargs == 0 && nkwargs == 0) || args != NULL); /* kwnames must only contains str strings, no subclass, and all keys must be unique */ - /* _PyCFunction_FastCallKeywords() must not be called with an exception - set, because it can clear it (directly or indirectly) and so the caller - loses its exception */ - assert(!PyErr_Occurred()); - - func = (PyCFunctionObject*)func_obj; - meth = PyCFunction_GET_FUNCTION(func); - self = PyCFunction_GET_SELF(func); - flags = PyCFunction_GET_FLAGS(func) & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + PyCFunction meth = method->ml_meth; + int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames); + PyObject *result; switch (flags) { @@ -248,7 +240,7 @@ _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, if (nargs != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", - func->m_ml->ml_name, nargs); + method->ml_name, nargs); return NULL; } @@ -263,7 +255,7 @@ _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, if (nargs != 1) { PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", - func->m_ml->ml_name, nargs); + method->ml_name, nargs); return NULL; } @@ -326,16 +318,31 @@ _PyCFunction_FastCallKeywords(PyObject *func_obj, PyObject **args, return NULL; } - result = _Py_CheckFunctionResult(func_obj, result, NULL); return result; no_keyword_error: PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", - func->m_ml->ml_name); + method->ml_name); return NULL; } +PyObject * +_PyCFunction_FastCallKeywords(PyObject *func, PyObject **args, + Py_ssize_t nargs, PyObject *kwnames) +{ + PyObject *result; + + assert(func != NULL); + assert(PyCFunction_Check(func)); + + result = _PyMethodDef_RawFastCallKeywords(((PyCFunctionObject*)func)->m_ml, + PyCFunction_GET_SELF(func), + args, nargs, kwnames); + result = _Py_CheckFunctionResult(func, result, NULL); + return result; +} + /* Methods (the standard built-in methods, that is) */ static void diff --git a/Objects/object.c b/Objects/object.c index 93cdc1014f..5da6cffdb9 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1060,8 +1060,8 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method) descr = _PyType_Lookup(tp, name); if (descr != NULL) { Py_INCREF(descr); - if (PyFunction_Check(descr)) { - /* A python method. */ + if (PyFunction_Check(descr) || + (Py_TYPE(descr) == &PyMethodDescr_Type)) { meth_found = 1; } else { f = descr->ob_type->tp_descr_get; -- cgit v1.2.1 From 9bfb9694a65124a8191cdb8ce7992445d1d0f4d2 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Sat, 4 Feb 2017 08:05:07 +0200 Subject: Issue #29311: Regenerate Argument Clinic. --- Objects/clinic/dictobject.c.h | 4 ++-- Objects/dictobject.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'Objects') diff --git a/Objects/clinic/dictobject.c.h b/Objects/clinic/dictobject.c.h index 97918e82a7..fb1e797de1 100644 --- a/Objects/clinic/dictobject.c.h +++ b/Objects/clinic/dictobject.c.h @@ -40,7 +40,7 @@ PyDoc_STRVAR(dict___contains____doc__, "__contains__($self, key, /)\n" "--\n" "\n" -"True if the dictionary has a specified key, else False."); +"True if the dictionary has the specified key, else False."); #define DICT___CONTAINS___METHODDEF \ {"__contains__", (PyCFunction)dict___contains__, METH_O|METH_COEXIST, dict___contains____doc__}, @@ -115,4 +115,4 @@ dict_setdefault(PyDictObject *self, PyObject **args, Py_ssize_t nargs, PyObject exit: return return_value; } -/*[clinic end generated code: output=91aa6a9f3c402b1b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=4d57df133cf66e53 input=a9049054013a1b77]*/ diff --git a/Objects/dictobject.c b/Objects/dictobject.c index 00fd58c81d..43584b7bb2 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -2769,7 +2769,7 @@ True if the dictionary has the specified key, else False. static PyObject * dict___contains__(PyDictObject *self, PyObject *key) -/*[clinic end generated code: output=a3d03db709ed6e6b input=f39613886bf975b7]*/ +/*[clinic end generated code: output=a3d03db709ed6e6b input=fe1cb42ad831e820]*/ { register PyDictObject *mp = self; Py_hash_t hash; -- cgit v1.2.1 From 7a46b9a1dd0da5ef1362330ee4c94ca1fdc06d0c Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Sat, 4 Feb 2017 02:43:42 -0800 Subject: Reduce load factor (from 66% to 60%) to improve effectiveness of linear probing. Decreased density gives better collision statistics (average of 2.5 probes in a full table versus 3.0 previously) and fewer occurences of starting a second possibly overlapping sequence of 10 linear probes. Makes resizes a little more frequent but each with less work (fewer insertions and fewer collisions). --- Objects/setobject.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'Objects') diff --git a/Objects/setobject.c b/Objects/setobject.c index c72c0fae62..4f04f49efa 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -234,7 +234,7 @@ set_add_entry(PySetObject *so, PyObject *key, Py_hash_t hash) so->used++; entry->key = key; entry->hash = hash; - if ((size_t)so->fill*3 < mask*2) + if ((size_t)so->fill*5 < mask*3) return 0; return set_table_resize(so, so->used); @@ -642,7 +642,7 @@ set_merge(PySetObject *so, PyObject *otherset) * incrementally resizing as we insert new keys. Expect * that there will be no (or few) overlapping keys. */ - if ((so->fill + other->used)*3 >= so->mask*2) { + if ((so->fill + other->used)*5 >= so->mask*3) { if (set_table_resize(so, so->used + other->used) != 0) return -1; } @@ -986,7 +986,7 @@ set_update_internal(PySetObject *so, PyObject *other) */ if (dictsize < 0) return -1; - if ((so->fill + dictsize)*3 >= so->mask*2) { + if ((so->fill + dictsize)*5 >= so->mask*3) { if (set_table_resize(so, so->used + dictsize) != 0) return -1; } -- cgit v1.2.1 From 54ab9ca906471f8a49e22c7f85d4f34c2ef7212c Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Mon, 6 Feb 2017 10:41:46 +0200 Subject: Issue #29460: _PyArg_NoKeywords(), _PyArg_NoStackKeywords() and _PyArg_NoPositional() now are macros. --- Objects/setobject.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'Objects') diff --git a/Objects/setobject.c b/Objects/setobject.c index 4f04f49efa..2ccf183e3c 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -1084,8 +1084,7 @@ frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *iterable = NULL, *result; - if (kwds != NULL && type == &PyFrozenSet_Type - && !_PyArg_NoKeywords("frozenset()", kwds)) + if (type == &PyFrozenSet_Type && !_PyArg_NoKeywords("frozenset()", kwds)) return NULL; if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable)) @@ -2002,7 +2001,7 @@ set_init(PySetObject *self, PyObject *args, PyObject *kwds) { PyObject *iterable = NULL; - if (kwds != NULL && !_PyArg_NoKeywords("set()", kwds)) + if (!_PyArg_NoKeywords("set()", kwds)) return -1; if (!PyArg_UnpackTuple(args, Py_TYPE(self)->tp_name, 0, 1, &iterable)) return -1; -- cgit v1.2.1 From b4e41f42fc0d0d07c18a8e2b752699c379ad3c78 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 8 Feb 2017 12:06:00 +0100 Subject: Issue #29306: Fix usage of Py_EnterRecursiveCall() * *PyCFunction_*Call*() functions now call Py_EnterRecursiveCall(). * PyObject_Call() now calls directly _PyFunction_FastCallDict() and PyCFunction_Call() to avoid calling Py_EnterRecursiveCall() twice per function call --- Objects/abstract.c | 102 ++++++++++++++++++++++++++----------------------- Objects/methodobject.c | 61 +++++++++++++++++------------ 2 files changed, 90 insertions(+), 73 deletions(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 1e394f865a..8d18313ed0 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2239,21 +2239,32 @@ PyObject_Call(PyObject *callable, PyObject *args, PyObject *kwargs) assert(PyTuple_Check(args)); assert(kwargs == NULL || PyDict_Check(kwargs)); - call = callable->ob_type->tp_call; - if (call == NULL) { - PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", - callable->ob_type->tp_name); - return NULL; + if (PyFunction_Check(callable)) { + return _PyFunction_FastCallDict(callable, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args), + kwargs); + } + else if (PyCFunction_Check(callable)) { + return PyCFunction_Call(callable, args, kwargs); } + else { + call = callable->ob_type->tp_call; + if (call == NULL) { + PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", + callable->ob_type->tp_name); + return NULL; + } - if (Py_EnterRecursiveCall(" while calling a Python object")) - return NULL; + if (Py_EnterRecursiveCall(" while calling a Python object")) + return NULL; - result = (*call)(callable, args, kwargs); + result = (*call)(callable, args, kwargs); - Py_LeaveRecursiveCall(); + Py_LeaveRecursiveCall(); - return _Py_CheckFunctionResult(callable, result, NULL); + return _Py_CheckFunctionResult(callable, result, NULL); + } } /* Issue #29234: Inlining _PyStack_AsTuple() into callers increases their @@ -2305,9 +2316,6 @@ PyObject * _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { - ternaryfunc call; - PyObject *result = NULL; - /* _PyObject_FastCallDict() must not be called with an exception set, because it can clear it (directly or indirectly) and so the caller loses its exception */ @@ -2318,42 +2326,41 @@ _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; - } - if (PyFunction_Check(callable)) { - result = _PyFunction_FastCallDict(callable, args, nargs, kwargs); + return _PyFunction_FastCallDict(callable, args, nargs, kwargs); } else if (PyCFunction_Check(callable)) { - result = _PyCFunction_FastCallDict(callable, args, nargs, kwargs); + return _PyCFunction_FastCallDict(callable, args, nargs, kwargs); } else { - PyObject *tuple; + PyObject *argstuple, *result; + ternaryfunc call; /* Slow-path: build a temporary tuple */ call = callable->ob_type->tp_call; if (call == NULL) { PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", callable->ob_type->tp_name); - goto exit; + return NULL; } - tuple = _PyStack_AsTuple(args, nargs); - if (tuple == NULL) { - goto exit; + argstuple = _PyStack_AsTuple(args, nargs); + if (argstuple == NULL) { + return NULL; } - result = (*call)(callable, tuple, kwargs); - Py_DECREF(tuple); + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } - result = _Py_CheckFunctionResult(callable, result, NULL); - } + result = (*call)(callable, argstuple, kwargs); -exit: - Py_LeaveRecursiveCall(); + Py_LeaveRecursiveCall(); - return result; + Py_DECREF(argstuple); + result = _Py_CheckFunctionResult(callable, result, NULL); + return result; + } } /* Positional arguments are obj followed by args: @@ -2506,49 +2513,48 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg temporary dictionary for keyword arguments (if any) */ ternaryfunc call; - PyObject *argtuple; + PyObject *argstuple; PyObject *kwdict, *result; Py_ssize_t nkwargs; - result = NULL; nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames); assert((nargs == 0 && nkwargs == 0) || stack != NULL); - if (Py_EnterRecursiveCall(" while calling a Python object")) { - return NULL; - } - call = callable->ob_type->tp_call; if (call == NULL) { PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable", callable->ob_type->tp_name); - goto exit; + return NULL; } - argtuple = _PyStack_AsTuple(stack, nargs); - if (argtuple == NULL) { - goto exit; + argstuple = _PyStack_AsTuple(stack, nargs); + if (argstuple == NULL) { + return NULL; } if (nkwargs > 0) { kwdict = _PyStack_AsDict(stack + nargs, kwnames); if (kwdict == NULL) { - Py_DECREF(argtuple); - goto exit; + Py_DECREF(argstuple); + return NULL; } } else { kwdict = NULL; } - result = (*call)(callable, argtuple, kwdict); - Py_DECREF(argtuple); - Py_XDECREF(kwdict); + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } - result = _Py_CheckFunctionResult(callable, result, NULL); + result = (*call)(callable, argstuple, kwdict); - exit: Py_LeaveRecursiveCall(); + + Py_DECREF(argstuple); + Py_XDECREF(kwdict); + + result = _Py_CheckFunctionResult(callable, result, NULL); return result; } } diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 6618d78968..07827775ca 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -90,11 +90,6 @@ PyObject * _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwargs) { - PyCFunction meth; - PyObject *result; - int flags; - PyObject *argstuple; - /* _PyMethodDef_RawFastCallDict() must not be called with an exception set, because it can clear it (directly or indirectly) and so the caller loses its exception */ @@ -105,18 +100,23 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg assert(nargs == 0 || args != NULL); assert(kwargs == NULL || PyDict_Check(kwargs)); - meth = method->ml_meth; - flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + PyCFunction meth = method->ml_meth; + int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); + PyObject *result = NULL; + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } switch (flags) { case METH_NOARGS: - if (nargs != 0) { + if (nargs != 0) { PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", method->ml_name, nargs); - return NULL; - } + goto exit; + } if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { goto no_keyword_error; @@ -130,7 +130,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", method->ml_name, nargs); - return NULL; + goto exit; } if (kwargs != NULL && PyDict_GET_SIZE(kwargs) != 0) { @@ -148,10 +148,11 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg /* fall through next case */ case METH_VARARGS | METH_KEYWORDS: + { /* Slow-path: create a temporary tuple for positional arguments */ - argstuple = _PyStack_AsTuple(args, nargs); + PyObject *argstuple = _PyStack_AsTuple(args, nargs); if (argstuple == NULL) { - return NULL; + goto exit; } if (flags & METH_KEYWORDS) { @@ -162,6 +163,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg } Py_DECREF(argstuple); break; + } case METH_FASTCALL: { @@ -170,7 +172,7 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg _PyCFunctionFast fastmeth = (_PyCFunctionFast)meth; if (_PyStack_UnpackDict(args, nargs, kwargs, &stack, &kwnames) < 0) { - return NULL; + goto exit; } result = (*fastmeth) (self, stack, nargs, kwnames); @@ -185,17 +187,19 @@ _PyMethodDef_RawFastCallDict(PyMethodDef *method, PyObject *self, PyObject **arg PyErr_SetString(PyExc_SystemError, "Bad call flags in _PyMethodDef_RawFastCallDict. " "METH_OLDARGS is no longer supported!"); - return NULL; + goto exit; } - return result; + goto exit; no_keyword_error: PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", method->ml_name, nargs); - return NULL; +exit: + Py_LeaveRecursiveCall(); + return result; } PyObject * @@ -232,7 +236,11 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * PyCFunction meth = method->ml_meth; int flags = method->ml_flags & ~(METH_CLASS | METH_STATIC | METH_COEXIST); Py_ssize_t nkwargs = kwnames == NULL ? 0 : PyTuple_Size(kwnames); - PyObject *result; + PyObject *result = NULL; + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } switch (flags) { @@ -241,7 +249,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * PyErr_Format(PyExc_TypeError, "%.200s() takes no arguments (%zd given)", method->ml_name, nargs); - return NULL; + goto exit; } if (nkwargs) { @@ -256,7 +264,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * PyErr_Format(PyExc_TypeError, "%.200s() takes exactly one argument (%zd given)", method->ml_name, nargs); - return NULL; + goto exit; } if (nkwargs) { @@ -284,7 +292,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * argtuple = _PyStack_AsTuple(args, nargs); if (argtuple == NULL) { - return NULL; + goto exit; } if (flags & METH_KEYWORDS) { @@ -294,7 +302,7 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * kwdict = _PyStack_AsDict(args + nargs, kwnames); if (kwdict == NULL) { Py_DECREF(argtuple); - return NULL; + goto exit; } } else { @@ -315,16 +323,19 @@ _PyMethodDef_RawFastCallKeywords(PyMethodDef *method, PyObject *self, PyObject * PyErr_SetString(PyExc_SystemError, "Bad call flags in _PyCFunction_FastCallKeywords. " "METH_OLDARGS is no longer supported!"); - return NULL; + goto exit; } - return result; + goto exit; no_keyword_error: PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", method->ml_name); - return NULL; + +exit: + Py_LeaveRecursiveCall(); + return result; } PyObject * -- cgit v1.2.1 From dedb0fac27238797f6923be5923c2021bcb02376 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 8 Feb 2017 12:57:09 +0100 Subject: Fix refleaks if Py_EnterRecursiveCall() fails Issue #29306: Destroy argstuple and kwdict if Py_EnterRecursiveCall() fails. --- Objects/abstract.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'Objects') diff --git a/Objects/abstract.c b/Objects/abstract.c index 8d18313ed0..4d7f94ad87 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -2350,14 +2350,15 @@ _PyObject_FastCallDict(PyObject *callable, PyObject **args, Py_ssize_t nargs, } if (Py_EnterRecursiveCall(" while calling a Python object")) { + Py_DECREF(argstuple); return NULL; } result = (*call)(callable, argstuple, kwargs); Py_LeaveRecursiveCall(); - Py_DECREF(argstuple); + result = _Py_CheckFunctionResult(callable, result, NULL); return result; } @@ -2544,6 +2545,8 @@ _PyObject_FastCallKeywords(PyObject *callable, PyObject **stack, Py_ssize_t narg } if (Py_EnterRecursiveCall(" while calling a Python object")) { + Py_DECREF(argstuple); + Py_XDECREF(kwdict); return NULL; } -- cgit v1.2.1 From bbd3587a29510bd5a318e0a19fc8570c0cd3b622 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 9 Feb 2017 02:01:37 +0100 Subject: Fix PyCFunction_Call() performance issue Issue #29259, #29465: PyCFunction_Call() doesn't create anymore a redundant tuple to pass positional arguments for METH_VARARGS. Add a new cfunction_call() subfunction. --- Objects/methodobject.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) (limited to 'Objects') diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 07827775ca..d0fbefd550 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -77,13 +77,59 @@ PyCFunction_GetFlags(PyObject *op) return PyCFunction_GET_FLAGS(op); } +static PyObject * +cfunction_call_varargs(PyObject *func, PyObject *args, PyObject *kwargs) +{ + assert(!PyErr_Occurred()); + + PyCFunction meth = PyCFunction_GET_FUNCTION(func); + PyObject *self = PyCFunction_GET_SELF(func); + PyObject *result; + + if (PyCFunction_GET_FLAGS(func) & METH_KEYWORDS) { + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + result = (*(PyCFunctionWithKeywords)meth)(self, args, kwargs); + + Py_LeaveRecursiveCall(); + } + else { + if (kwargs != NULL && PyDict_Size(kwargs) != 0) { + PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments", + ((PyCFunctionObject*)func)->m_ml->ml_name); + return NULL; + } + + if (Py_EnterRecursiveCall(" while calling a Python object")) { + return NULL; + } + + result = (*meth)(self, args); + + Py_LeaveRecursiveCall(); + } + + return _Py_CheckFunctionResult(func, result, NULL); +} + + PyObject * PyCFunction_Call(PyObject *func, PyObject *args, PyObject *kwargs) { - return _PyCFunction_FastCallDict(func, - &PyTuple_GET_ITEM(args, 0), - PyTuple_GET_SIZE(args), - kwargs); + /* first try METH_VARARGS to pass directly args tuple unchanged. + _PyMethodDef_RawFastCallDict() creates a new temporary tuple + for METH_VARARGS. */ + if (PyCFunction_GET_FLAGS(func) & METH_VARARGS) { + return cfunction_call_varargs(func, args, kwargs); + } + else { + return _PyCFunction_FastCallDict(func, + &PyTuple_GET_ITEM(args, 0), + PyTuple_GET_SIZE(args), + kwargs); + } } PyObject * -- cgit v1.2.1