From ee9c0527ae4b3868ab6162bb6f423645bf182022 Mon Sep 17 00:00:00 2001 From: Mark Shannon Date: Fri, 27 Aug 2021 12:01:22 +0100 Subject: [PATCH] Refine specialization stats (GH-27992) --- Python/specialize.c | 106 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 89 insertions(+), 17 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index b321368148f..6c76fa6b05f 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -405,6 +405,7 @@ _Py_Quicken(PyCodeObject *code) { /* Common */ +#define SPEC_FAIL_OTHER 0 #define SPEC_FAIL_NO_DICT 1 #define SPEC_FAIL_OVERRIDDEN 2 #define SPEC_FAIL_OUT_OF_VERSIONS 3 @@ -427,24 +428,28 @@ _Py_Quicken(PyCodeObject *code) { /* Methods */ -#define SPEC_FAIL_NEGATIVE_DICTOFFSET 14 #define SPEC_FAIL_IS_ATTR 15 #define SPEC_FAIL_DICT_SUBCLASS 16 #define SPEC_FAIL_BUILTIN_CLASS_METHOD 17 #define SPEC_FAIL_CLASS_METHOD_OBJ 18 -#define SPEC_FAIL_NOT_METHOD 19 +#define SPEC_FAIL_OBJECT_SLOT 19 /* Binary subscr */ -#define SPEC_FAIL_LIST_NON_INT_SUBSCRIPT 8 -#define SPEC_FAIL_TUPLE_NON_INT_SUBSCRIPT 9 -#define SPEC_FAIL_NOT_TUPLE_LIST_OR_DICT 10 +#define SPEC_FAIL_ARRAY_INT 8 +#define SPEC_FAIL_ARRAY_SLICE 9 +#define SPEC_FAIL_LIST_SLICE 10 +#define SPEC_FAIL_TUPLE_SLICE 11 +#define SPEC_FAIL_STRING_INT 12 +#define SPEC_FAIL_STRING_SLICE 13 +#define SPEC_FAIL_BUFFER_INT 15 +#define SPEC_FAIL_BUFFER_SLICE 16 +#define SPEC_FAIL_SEQUENCE_INT 17 /* Binary add */ #define SPEC_FAIL_NON_FUNCTION_SCOPE 11 #define SPEC_FAIL_DIFFERENT_TYPES 12 -#define SPEC_FAIL_OTHER_TYPE 13 static int @@ -870,7 +875,7 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, // Technically this is fine for bound method calls, but it's uncommon and // slightly slower at runtime to get dict. if (owner_cls->tp_dictoffset < 0) { - SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_NEGATIVE_DICTOFFSET); + SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_OUT_OF_RANGE); goto fail; } PyObject **owner_dictptr = _PyObject_GetDictPtr(owner); @@ -896,16 +901,43 @@ _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, assert(descr != NULL || kind == ABSENT || kind == GETSET_OVERRIDDEN); switch (kind) { + case OVERRIDING: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDING_DESCRIPTOR); + goto fail; case METHOD: break; + case PROPERTY: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_PROPERTY); + goto fail; + case OBJECT_SLOT: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OBJECT_SLOT); + goto fail; + case OTHER_SLOT: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_NON_OBJECT_SLOT); + goto fail; + case DUNDER_CLASS: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OTHER); + goto fail; + case MUTABLE: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_MUTABLE_CLASS); + goto fail; + case GETSET_OVERRIDDEN: + SPECIALIZATION_FAIL(LOAD_ATTR, SPEC_FAIL_OVERRIDDEN); + goto fail; case BUILTIN_CLASSMETHOD: SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_BUILTIN_CLASS_METHOD); goto fail; case PYTHON_CLASSMETHOD: SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_CLASS_METHOD_OBJ); goto fail; - default: - SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_NOT_METHOD); + case NON_OVERRIDING: + SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_NON_OVERRIDING_DESCRIPTOR); + goto fail; + case NON_DESCRIPTOR: + SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_NOT_DESCRIPTOR); + goto fail; + case ABSENT: + SPECIALIZATION_FAIL(LOAD_METHOD, SPEC_FAIL_EXPECTED_ERROR); goto fail; } @@ -1046,6 +1078,45 @@ success: return 0; } +#if COLLECT_SPECIALIZATION_STATS_DETAILED +static int +binary_subscr_faiL_kind(PyTypeObject *container_type, PyObject *sub) +{ + if (container_type == &PyUnicode_Type) { + if (PyLong_CheckExact(sub)) { + return SPEC_FAIL_STRING_INT; + } + if (PySlice_Check(sub)) { + return SPEC_FAIL_STRING_SLICE; + } + return SPEC_FAIL_OTHER; + } + else if (strcmp(container_type->tp_name, "array.array") == 0) { + if (PyLong_CheckExact(sub)) { + return SPEC_FAIL_ARRAY_INT; + } + if (PySlice_Check(sub)) { + return SPEC_FAIL_ARRAY_SLICE; + } + return SPEC_FAIL_OTHER; + } + else if (container_type->tp_as_buffer) { + if (PyLong_CheckExact(sub)) { + return SPEC_FAIL_BUFFER_INT; + } + if (PySlice_Check(sub)) { + return SPEC_FAIL_BUFFER_SLICE; + } + return SPEC_FAIL_OTHER; + } + else if (container_type->tp_as_sequence) { + if (PyLong_CheckExact(sub) && container_type->tp_as_sequence->sq_item) { + return SPEC_FAIL_SEQUENCE_INT; + } + } + return SPEC_FAIL_OTHER; +} +#endif int _Py_Specialize_BinarySubscr( PyObject *container, PyObject *sub, _Py_CODEUNIT *instr) @@ -1055,25 +1126,26 @@ _Py_Specialize_BinarySubscr( if (PyLong_CheckExact(sub)) { *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_LIST_INT, saturating_start()); goto success; - } else { - SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_LIST_NON_INT_SUBSCRIPT); - goto fail; } + SPECIALIZATION_FAIL(BINARY_SUBSCR, + PySlice_Check(sub) ? SPEC_FAIL_LIST_SLICE : SPEC_FAIL_OTHER); + goto fail; } if (container_type == &PyTuple_Type) { if (PyLong_CheckExact(sub)) { *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_TUPLE_INT, saturating_start()); goto success; - } else { - SPECIALIZATION_FAIL(BINARY_SUBSCR, SPEC_FAIL_TUPLE_NON_INT_SUBSCRIPT); - goto fail; } + SPECIALIZATION_FAIL(BINARY_SUBSCR, + PySlice_Check(sub) ? SPEC_FAIL_TUPLE_SLICE : SPEC_FAIL_OTHER); + goto fail; } if (container_type == &PyDict_Type) { *instr = _Py_MAKECODEUNIT(BINARY_SUBSCR_DICT, saturating_start()); goto success; } - SPECIALIZATION_FAIL(BINARY_SUBSCR,SPEC_FAIL_NOT_TUPLE_LIST_OR_DICT); + SPECIALIZATION_FAIL(BINARY_SUBSCR, + binary_subscr_faiL_kind(container_type, sub)); goto fail; fail: STAT_INC(BINARY_SUBSCR, specialization_failure); @@ -1114,7 +1186,7 @@ _Py_Specialize_BinaryAdd(PyObject *left, PyObject *right, _Py_CODEUNIT *instr) } else { - SPECIALIZATION_FAIL(BINARY_ADD, SPEC_FAIL_OTHER_TYPE); + SPECIALIZATION_FAIL(BINARY_ADD, SPEC_FAIL_OTHER); } fail: STAT_INC(BINARY_ADD, specialization_failure);