From a15e260b708a98edaba86a2aa663c3f6b2abc964 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 8 Apr 2020 02:01:56 +0200 Subject: [PATCH] bpo-40170: Add _PyIndex_Check() internal function (GH-19426) Add _PyIndex_Check() function to the internal C API: fast inlined verson of PyIndex_Check(). Add Include/internal/pycore_abstract.h header file. Replace PyIndex_Check() with _PyIndex_Check() in C files of Objects and Python subdirectories. --- Include/internal/pycore_abstract.h | 22 ++++++++++++++++++++++ Makefile.pre.in | 1 + Objects/abstract.c | 20 +++++++++++--------- Objects/bytearrayobject.c | 7 ++++--- Objects/bytes_methods.c | 3 ++- Objects/bytesobject.c | 5 +++-- Objects/interpreteridobject.c | 5 +++-- Objects/listobject.c | 5 +++-- Objects/memoryobject.c | 8 +++++--- Objects/rangeobject.c | 5 +++-- Objects/sliceobject.c | 3 ++- Objects/tupleobject.c | 3 ++- Objects/unicodeobject.c | 3 ++- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 +++ Python/ceval.c | 5 +++-- Python/modsupport.c | 3 ++- 17 files changed, 72 insertions(+), 30 deletions(-) create mode 100644 Include/internal/pycore_abstract.h diff --git a/Include/internal/pycore_abstract.h b/Include/internal/pycore_abstract.h new file mode 100644 index 00000000000..b791bf24321 --- /dev/null +++ b/Include/internal/pycore_abstract.h @@ -0,0 +1,22 @@ +#ifndef Py_INTERNAL_ABSTRACT_H +#define Py_INTERNAL_ABSTRACT_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +// Fast inlined version of PyIndex_Check() +static inline int +_PyIndex_Check(PyObject *obj) +{ + PyNumberMethods *tp_as_number = Py_TYPE(obj)->tp_as_number; + return (tp_as_number != NULL && tp_as_number->nb_index != NULL); +} + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_ABSTRACT_H */ diff --git a/Makefile.pre.in b/Makefile.pre.in index 948f9851d0c..ac6c2b12889 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1080,6 +1080,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/tupleobject.h \ $(srcdir)/Include/cpython/unicodeobject.h \ \ + $(srcdir)/Include/internal/pycore_abstract.h \ $(srcdir)/Include/internal/pycore_accu.h \ $(srcdir)/Include/internal/pycore_atomic.h \ $(srcdir)/Include/internal/pycore_bytes_methods.h \ diff --git a/Objects/abstract.c b/Objects/abstract.c index 49a38d8f6e2..b5d91dbab0c 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1,7 +1,8 @@ /* Abstract Object Interface (many thanks to Jim Fulton) */ #include "Python.h" -#include "pycore_ceval.h" // _Py_EnterRecursiveCall() +#include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_ceval.h" // _Py_EnterRecursiveCall() #include "pycore_pyerrors.h" #include "pycore_pystate.h" #include @@ -160,7 +161,7 @@ PyObject_GetItem(PyObject *o, PyObject *key) ms = Py_TYPE(o)->tp_as_sequence; if (ms && ms->sq_item) { - if (PyIndex_Check(key)) { + if (_PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) @@ -176,7 +177,7 @@ PyObject_GetItem(PyObject *o, PyObject *key) if (PyType_Check(o)) { PyObject *meth, *result; _Py_IDENTIFIER(__class_getitem__); - + // Special case type[int], but disallow other types so str[int] fails if ((PyTypeObject*)o == &PyType_Type) { return Py_GenericAlias(o, key); @@ -209,7 +210,7 @@ PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value) return m->mp_ass_subscript(o, key, value); if (Py_TYPE(o)->tp_as_sequence) { - if (PyIndex_Check(key)) { + if (_PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) @@ -241,7 +242,7 @@ PyObject_DelItem(PyObject *o, PyObject *key) return m->mp_ass_subscript(o, key, (PyObject*)NULL); if (Py_TYPE(o)->tp_as_sequence) { - if (PyIndex_Check(key)) { + if (_PyIndex_Check(key)) { Py_ssize_t key_value; key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) @@ -1030,7 +1031,7 @@ static PyObject * sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) { Py_ssize_t count; - if (PyIndex_Check(n)) { + if (_PyIndex_Check(n)) { count = PyNumber_AsSsize_t(n, PyExc_OverflowError); if (count == -1 && PyErr_Occurred()) return NULL; @@ -1307,15 +1308,16 @@ PyNumber_Absolute(PyObject *o) return type_error("bad operand type for abs(): '%.200s'", o); } + #undef PyIndex_Check int PyIndex_Check(PyObject *obj) { - return Py_TYPE(obj)->tp_as_number != NULL && - Py_TYPE(obj)->tp_as_number->nb_index != NULL; + return _PyIndex_Check(obj); } + /* Return a Python int from the object item. Raise TypeError if the result is not an int or if the object cannot be interpreted as an index. @@ -1332,7 +1334,7 @@ PyNumber_Index(PyObject *item) Py_INCREF(item); return item; } - if (!PyIndex_Check(item)) { + if (!_PyIndex_Check(item)) { PyErr_Format(PyExc_TypeError, "'%.200s' object cannot be interpreted " "as an integer", Py_TYPE(item)->tp_name); diff --git a/Objects/bytearrayobject.c b/Objects/bytearrayobject.c index d3964358bc5..7ebfa1f9434 100644 --- a/Objects/bytearrayobject.c +++ b/Objects/bytearrayobject.c @@ -2,6 +2,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_bytes_methods.h" #include "pycore_object.h" #include "pycore_pymem.h" @@ -391,7 +392,7 @@ bytearray_getitem(PyByteArrayObject *self, Py_ssize_t i) static PyObject * bytearray_subscript(PyByteArrayObject *self, PyObject *index) { - if (PyIndex_Check(index)) { + if (_PyIndex_Check(index)) { Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) @@ -610,7 +611,7 @@ bytearray_ass_subscript(PyByteArrayObject *self, PyObject *index, PyObject *valu char *buf, *bytes; buf = PyByteArray_AS_STRING(self); - if (PyIndex_Check(index)) { + if (_PyIndex_Check(index)) { Py_ssize_t i = PyNumber_AsSsize_t(index, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) @@ -809,7 +810,7 @@ bytearray_init(PyByteArrayObject *self, PyObject *args, PyObject *kwds) } /* Is it an int? */ - if (PyIndex_Check(arg)) { + if (_PyIndex_Check(arg)) { count = PyNumber_AsSsize_t(arg, PyExc_OverflowError); if (count == -1 && PyErr_Occurred()) { if (!PyErr_ExceptionMatches(PyExc_TypeError)) diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c index a4b3868e725..72daa1fdd55 100644 --- a/Objects/bytes_methods.c +++ b/Objects/bytes_methods.c @@ -1,5 +1,6 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_bytes_methods.h" PyDoc_STRVAR_shared(_Py_isspace__doc__, @@ -466,7 +467,7 @@ parse_args_finds_byte(const char *function_name, PyObject *args, return 1; } - if (!PyIndex_Check(tmp_subobj)) { + if (!_PyIndex_Check(tmp_subobj)) { PyErr_Format(PyExc_TypeError, "argument should be integer or bytes-like object, " "not '%.200s'", diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index bd8af72ade5..03cd7ddd279 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -3,6 +3,7 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_bytes_methods.h" #include "pycore_object.h" #include "pycore_pymem.h" @@ -1579,7 +1580,7 @@ bytes_hash(PyBytesObject *a) static PyObject* bytes_subscript(PyBytesObject* self, PyObject* item) { - if (PyIndex_Check(item)) { + if (_PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; @@ -2536,7 +2537,7 @@ bytes_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return NULL; } /* Is it an integer? */ - if (PyIndex_Check(x)) { + if (_PyIndex_Check(x)) { size = PyNumber_AsSsize_t(x, PyExc_OverflowError); if (size == -1 && PyErr_Occurred()) { if (!PyErr_ExceptionMatches(PyExc_TypeError)) diff --git a/Objects/interpreteridobject.c b/Objects/interpreteridobject.c index 57748e8139f..3f316873ed5 100644 --- a/Objects/interpreteridobject.c +++ b/Objects/interpreteridobject.c @@ -1,7 +1,8 @@ /* InterpreterID object */ #include "Python.h" -#include "internal/pycore_pystate.h" +#include "pycore_abstract.h" // _PyIndex_Check() +#include "pycore_pystate.h" #include "interpreteridobject.h" @@ -42,7 +43,7 @@ interp_id_converter(PyObject *arg, void *ptr) if (PyObject_TypeCheck(arg, &_PyInterpreterID_Type)) { id = ((interpid *)arg)->id; } - else if (PyIndex_Check(arg)) { + else if (_PyIndex_Check(arg)) { id = PyLong_AsLongLong(arg); if (id == -1 && PyErr_Occurred()) { return 0; diff --git a/Objects/listobject.c b/Objects/listobject.c index 48063b285f6..7058fe4396e 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -1,6 +1,7 @@ /* List object implementation */ #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_object.h" #include "pycore_pystate.h" #include "pycore_tupleobject.h" @@ -2800,7 +2801,7 @@ static PySequenceMethods list_as_sequence = { static PyObject * list_subscript(PyListObject* self, PyObject* item) { - if (PyIndex_Check(item)) { + if (_PyIndex_Check(item)) { Py_ssize_t i; i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) @@ -2855,7 +2856,7 @@ list_subscript(PyListObject* self, PyObject* item) static int list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) { - if (PyIndex_Check(item)) { + if (_PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return -1; diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 7f9c90035f5..da06338017c 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -11,6 +11,7 @@ */ #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_object.h" #include "pycore_pymem.h" #include "pycore_pystate.h" @@ -2421,8 +2422,9 @@ is_multiindex(PyObject *key) size = PyTuple_GET_SIZE(key); for (i = 0; i < size; i++) { PyObject *x = PyTuple_GET_ITEM(key, i); - if (!PyIndex_Check(x)) + if (!_PyIndex_Check(x)) { return 0; + } } return 1; } @@ -2459,7 +2461,7 @@ memory_subscript(PyMemoryViewObject *self, PyObject *key) } } - if (PyIndex_Check(key)) { + if (_PyIndex_Check(key)) { Py_ssize_t index; index = PyNumber_AsSsize_t(key, PyExc_IndexError); if (index == -1 && PyErr_Occurred()) @@ -2530,7 +2532,7 @@ memory_ass_sub(PyMemoryViewObject *self, PyObject *key, PyObject *value) } } - if (PyIndex_Check(key)) { + if (_PyIndex_Check(key)) { Py_ssize_t index; if (1 < view->ndim) { PyErr_SetString(PyExc_NotImplementedError, diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 5bd178b2027..4bea8d78e12 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -1,8 +1,9 @@ /* Range object implementation */ #include "Python.h" -#include "structmember.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_tupleobject.h" +#include "structmember.h" /* Support objects whose length is > PY_SSIZE_T_MAX. @@ -631,7 +632,7 @@ range_reduce(rangeobject *r, PyObject *args) static PyObject * range_subscript(rangeobject* self, PyObject* item) { - if (PyIndex_Check(item)) { + if (_PyIndex_Check(item)) { PyObject *i, *result; i = PyNumber_Index(item); if (!i) diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c index e884a589435..4fd216388fd 100644 --- a/Objects/sliceobject.c +++ b/Objects/sliceobject.c @@ -14,6 +14,7 @@ this type and there is exactly one in existence. */ #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_object.h" #include "pycore_pymem.h" #include "pycore_pystate.h" @@ -354,7 +355,7 @@ static PyMemberDef slice_members[] = { static PyObject* evaluate_slice_index(PyObject *v) { - if (PyIndex_Check(v)) { + if (_PyIndex_Check(v)) { return PyNumber_Index(v); } else { diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 68163d8c48c..110c0925ccd 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -2,6 +2,7 @@ /* Tuple object implementation */ #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_object.h" #include "pycore_pystate.h" #include "pycore_accu.h" @@ -763,7 +764,7 @@ static PySequenceMethods tuple_as_sequence = { static PyObject* tuplesubscript(PyTupleObject* self, PyObject* item) { - if (PyIndex_Check(item)) { + if (_PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index da17bfe01f3..1e1f257dad0 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -40,6 +40,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_bytes_methods.h" #include "pycore_fileutils.h" #include "pycore_initconfig.h" @@ -14132,7 +14133,7 @@ unicode_subscript(PyObject* self, PyObject* item) if (PyUnicode_READY(self) == -1) return NULL; - if (PyIndex_Check(item)) { + if (_PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 22f1b95d0a7..95f9e9b445f 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -161,6 +161,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 00891001ce0..32da3659d34 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -186,6 +186,9 @@ Include + + Include + Include diff --git a/Python/ceval.c b/Python/ceval.c index d79a239704f..7747b084f08 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -10,6 +10,7 @@ #define PY_LOCAL_AGGRESSIVE #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_call.h" #include "pycore_ceval.h" #include "pycore_code.h" @@ -5089,7 +5090,7 @@ _PyEval_SliceIndex(PyObject *v, Py_ssize_t *pi) PyThreadState *tstate = _PyThreadState_GET(); if (v != Py_None) { Py_ssize_t x; - if (PyIndex_Check(v)) { + if (_PyIndex_Check(v)) { x = PyNumber_AsSsize_t(v, NULL); if (x == -1 && _PyErr_Occurred(tstate)) return 0; @@ -5110,7 +5111,7 @@ _PyEval_SliceIndexNotNone(PyObject *v, Py_ssize_t *pi) { PyThreadState *tstate = _PyThreadState_GET(); Py_ssize_t x; - if (PyIndex_Check(v)) { + if (_PyIndex_Check(v)) { x = PyNumber_AsSsize_t(v, NULL); if (x == -1 && _PyErr_Occurred(tstate)) return 0; diff --git a/Python/modsupport.c b/Python/modsupport.c index a8e78c3cec8..845bdcb2b6f 100644 --- a/Python/modsupport.c +++ b/Python/modsupport.c @@ -2,6 +2,7 @@ /* Module support implementation */ #include "Python.h" +#include "pycore_abstract.h" // _PyIndex_Check() #define FLAG_SIZE_T 1 typedef double va_double; @@ -20,7 +21,7 @@ _Py_convert_optional_to_ssize_t(PyObject *obj, void *result) if (obj == Py_None) { return 1; } - else if (PyIndex_Check(obj)) { + else if (_PyIndex_Check(obj)) { limit = PyNumber_AsSsize_t(obj, PyExc_OverflowError); if (limit == -1 && PyErr_Occurred()) { return 0;