diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h index 2839b9b7ebe0fb..7457d8910f5604 100644 --- a/Include/internal/pycore_code.h +++ b/Include/internal/pycore_code.h @@ -315,6 +315,7 @@ extern void _Py_Specialize_ForIter(_PyStackRef iter, _Py_CODEUNIT *instr, int op extern void _Py_Specialize_Send(_PyStackRef receiver, _Py_CODEUNIT *instr); extern void _Py_Specialize_ToBool(_PyStackRef value, _Py_CODEUNIT *instr); extern void _Py_Specialize_ContainsOp(_PyStackRef value, _Py_CODEUNIT *instr); +extern void _Py_GatherStats_GetIter(_PyStackRef iterable); // Utility functions for reading/writing 32/64-bit values in the inline caches. // Great care should be taken to ensure that these functions remain correct and diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 95786c91371e98..1b1cc007480c12 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -3026,6 +3026,9 @@ dummy_func( } inst(GET_ITER, (iterable -- iter)) { + #ifdef Py_STATS + _Py_GatherStats_GetIter(iterable); + #endif /* before: [obj]; after [getiter(obj)] */ PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); PyStackRef_CLOSE(iterable); diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 9bfb13e2d9773f..48b28aeb223510 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4076,6 +4076,11 @@ _PyStackRef iterable; _PyStackRef iter; iterable = stack_pointer[-1]; + #ifdef Py_STATS + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_GatherStats_GetIter(iterable); + stack_pointer = _PyFrame_GetStackPointer(frame); + #endif _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); stack_pointer = _PyFrame_GetStackPointer(frame); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 6fe647d6197a07..6bb87edf8b3673 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -5920,6 +5920,11 @@ _PyStackRef iterable; _PyStackRef iter; iterable = stack_pointer[-1]; + #ifdef Py_STATS + _PyFrame_SetStackPointer(frame, stack_pointer); + _Py_GatherStats_GetIter(iterable); + stack_pointer = _PyFrame_GetStackPointer(frame); + #endif _PyFrame_SetStackPointer(frame, stack_pointer); PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable)); stack_pointer = _PyFrame_GetStackPointer(frame); diff --git a/Python/specialize.c b/Python/specialize.c index ceb396c5b54815..618b8249ebbd71 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -146,6 +146,7 @@ print_spec_stats(FILE *out, OpcodeStats *stats) * even though we don't specialize them yet. */ fprintf(out, "opcode[BINARY_SLICE].specializable : 1\n"); fprintf(out, "opcode[STORE_SLICE].specializable : 1\n"); + fprintf(out, "opcode[GET_ITER].specializable : 1\n"); for (int i = 0; i < 256; i++) { if (_PyOpcode_Caches[i]) { /* Ignore jumps as they cannot be specialized */ @@ -668,6 +669,7 @@ _PyCode_Quicken(_Py_CODEUNIT *instructions, Py_ssize_t size, int enable_counters #define SPEC_FAIL_ITER_CALLABLE 28 #define SPEC_FAIL_ITER_ASCII_STRING 29 #define SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND 30 +#define SPEC_FAIL_ITER_SELF 31 // UNPACK_SEQUENCE @@ -3114,6 +3116,53 @@ _Py_Specialize_ContainsOp(_PyStackRef value_st, _Py_CODEUNIT *instr) return; } +#ifdef Py_STATS +void +_Py_GatherStats_GetIter(_PyStackRef iterable) +{ + PyTypeObject *tp = PyStackRef_TYPE(iterable); + int kind = SPEC_FAIL_OTHER; + if (tp == &PyTuple_Type) { + kind = SPEC_FAIL_ITER_TUPLE; + } + else if (tp == &PyList_Type) { + kind = SPEC_FAIL_ITER_LIST; + } + else if (tp == &PyDict_Type) { + kind = SPEC_FAIL_ITER_DICT_KEYS; + } + else if (tp == &PySet_Type) { + kind = SPEC_FAIL_ITER_SET; + } + else if (tp == &PyBytes_Type) { + kind = SPEC_FAIL_ITER_BYTES; + } + else if (tp == &PyEnum_Type) { + kind = SPEC_FAIL_ITER_ENUMERATE; + } + else if (tp == &PyUnicode_Type) { + kind = SPEC_FAIL_ITER_STRING; + } + else if (tp == &PyGen_Type) { + kind = SPEC_FAIL_ITER_GENERATOR; + } + else if (tp == &PyCoro_Type) { + kind = SPEC_FAIL_ITER_COROUTINE; + } + else if (tp == &PyAsyncGen_Type) { + kind = SPEC_FAIL_ITER_ASYNC_GENERATOR; + } + else if (tp == &_PyAsyncGenASend_Type) { + kind = SPEC_FAIL_ITER_ASYNC_GENERATOR_SEND; + } + else if (tp->tp_iter == PyObject_SelfIter) { + kind = SPEC_FAIL_ITER_SELF; + } + SPECIALIZATION_FAIL(GET_ITER, kind); +} +#endif + + /* Code init cleanup. * CALL_ALLOC_AND_ENTER_INIT will set up * the frame to execute the EXIT_INIT_CHECK diff --git a/Tools/scripts/summarize_stats.py b/Tools/scripts/summarize_stats.py index eb54b8dd115c94..68cfad3f92cdc7 100644 --- a/Tools/scripts/summarize_stats.py +++ b/Tools/scripts/summarize_stats.py @@ -288,7 +288,7 @@ def kind_to_text(kind: int, opcode: str): opcode = "SUPER" elif opcode.endswith("ATTR"): opcode = "ATTR" - elif opcode in ("FOR_ITER", "SEND"): + elif opcode in ("FOR_ITER", "GET_ITER", "SEND"): opcode = "ITER" elif opcode.endswith("SUBSCR"): opcode = "SUBSCR"