From b899628becf54ff64e7b9af0abe6845927aad4ee Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Tue, 21 Jun 2022 14:37:35 -0400 Subject: [PATCH 1/5] get FOR_ITER_TUPLE working --- Include/internal/pycore_opcode.h | 57 ++++++++++++++------------- Include/internal/pycore_tuple.h | 6 +++ Include/opcode.h | 67 +++++++++++++++++--------------- Lib/opcode.py | 3 ++ Objects/tupleobject.c | 24 +++++------- Python/ceval.c | 29 ++++++++++++++ Python/opcode_targets.h | 48 +++++++++++------------ Python/specialize.c | 4 ++ 8 files changed, 140 insertions(+), 98 deletions(-) diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h index b9195f5c3299dc..a0fc9a60604791 100644 --- a/Include/internal/pycore_opcode.h +++ b/Include/internal/pycore_opcode.h @@ -125,8 +125,11 @@ const uint8_t _PyOpcode_Deopt[256] = { [FORMAT_VALUE] = FORMAT_VALUE, [FOR_ITER] = FOR_ITER, [FOR_ITER_ADAPTIVE] = FOR_ITER, + [FOR_ITER_DICT_ITEMS] = FOR_ITER, + [FOR_ITER_ENUMERATE] = FOR_ITER, [FOR_ITER_LIST] = FOR_ITER, [FOR_ITER_RANGE] = FOR_ITER, + [FOR_ITER_TUPLE] = FOR_ITER, [GET_AITER] = GET_AITER, [GET_ANEXT] = GET_ANEXT, [GET_AWAITABLE] = GET_AWAITABLE, @@ -309,8 +312,11 @@ const uint8_t _PyOpcode_Original[256] = { [FORMAT_VALUE] = FORMAT_VALUE, [FOR_ITER] = FOR_ITER, [FOR_ITER_ADAPTIVE] = FOR_ITER, + [FOR_ITER_DICT_ITEMS] = FOR_ITER, + [FOR_ITER_ENUMERATE] = FOR_ITER, [FOR_ITER_LIST] = FOR_ITER, [FOR_ITER_RANGE] = FOR_ITER, + [FOR_ITER_TUPLE] = FOR_ITER, [GET_AITER] = GET_AITER, [GET_ANEXT] = GET_ANEXT, [GET_AWAITABLE] = GET_AWAITABLE, @@ -488,29 +494,29 @@ static const char *const _PyOpcode_OpName[256] = { [DELETE_SUBSCR] = "DELETE_SUBSCR", [FOR_ITER_LIST] = "FOR_ITER_LIST", [FOR_ITER_RANGE] = "FOR_ITER_RANGE", + [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE", + [FOR_ITER_DICT_ITEMS] = "FOR_ITER_DICT_ITEMS", + [FOR_ITER_ENUMERATE] = "FOR_ITER_ENUMERATE", [JUMP_BACKWARD_QUICK] = "JUMP_BACKWARD_QUICK", - [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", - [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", - [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", [GET_ITER] = "GET_ITER", [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER", [PRINT_EXPR] = "PRINT_EXPR", [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS", - [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", - [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", + [LOAD_ATTR_ADAPTIVE] = "LOAD_ATTR_ADAPTIVE", + [LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS", [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR", [RETURN_GENERATOR] = "RETURN_GENERATOR", + [LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE", + [LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE", + [LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY", [LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT", [LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT", [LOAD_ATTR_METHOD_LAZY_DICT] = "LOAD_ATTR_METHOD_LAZY_DICT", - [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", - [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", - [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [LIST_TO_TUPLE] = "LIST_TO_TUPLE", [RETURN_VALUE] = "RETURN_VALUE", [IMPORT_STAR] = "IMPORT_STAR", [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS", - [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", + [LOAD_ATTR_METHOD_NO_DICT] = "LOAD_ATTR_METHOD_NO_DICT", [ASYNC_GEN_WRAP] = "ASYNC_GEN_WRAP", [PREP_RERAISE_STAR] = "PREP_RERAISE_STAR", [POP_EXCEPT] = "POP_EXCEPT", @@ -537,7 +543,7 @@ static const char *const _PyOpcode_OpName[256] = { [JUMP_FORWARD] = "JUMP_FORWARD", [JUMP_IF_FALSE_OR_POP] = "JUMP_IF_FALSE_OR_POP", [JUMP_IF_TRUE_OR_POP] = "JUMP_IF_TRUE_OR_POP", - [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", + [LOAD_ATTR_METHOD_WITH_DICT] = "LOAD_ATTR_METHOD_WITH_DICT", [POP_JUMP_FORWARD_IF_FALSE] = "POP_JUMP_FORWARD_IF_FALSE", [POP_JUMP_FORWARD_IF_TRUE] = "POP_JUMP_FORWARD_IF_TRUE", [LOAD_GLOBAL] = "LOAD_GLOBAL", @@ -545,7 +551,7 @@ static const char *const _PyOpcode_OpName[256] = { [CONTAINS_OP] = "CONTAINS_OP", [RERAISE] = "RERAISE", [COPY] = "COPY", - [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", + [LOAD_ATTR_METHOD_WITH_VALUES] = "LOAD_ATTR_METHOD_WITH_VALUES", [BINARY_OP] = "BINARY_OP", [SEND] = "SEND", [LOAD_FAST] = "LOAD_FAST", @@ -565,9 +571,9 @@ static const char *const _PyOpcode_OpName[256] = { [STORE_DEREF] = "STORE_DEREF", [DELETE_DEREF] = "DELETE_DEREF", [JUMP_BACKWARD] = "JUMP_BACKWARD", - [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", + [LOAD_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST", [CALL_FUNCTION_EX] = "CALL_FUNCTION_EX", - [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST", [EXTENDED_ARG] = "EXTENDED_ARG", [LIST_APPEND] = "LIST_APPEND", [SET_ADD] = "SET_ADD", @@ -577,37 +583,37 @@ static const char *const _PyOpcode_OpName[256] = { [YIELD_VALUE] = "YIELD_VALUE", [RESUME] = "RESUME", [MATCH_CLASS] = "MATCH_CLASS", - [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", - [RESUME_QUICK] = "RESUME_QUICK", + [LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST", + [LOAD_GLOBAL_ADAPTIVE] = "LOAD_GLOBAL_ADAPTIVE", [FORMAT_VALUE] = "FORMAT_VALUE", [BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP", [BUILD_STRING] = "BUILD_STRING", + [LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN", + [LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE", + [RESUME_QUICK] = "RESUME_QUICK", [STORE_ATTR_ADAPTIVE] = "STORE_ATTR_ADAPTIVE", - [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", - [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", - [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [LIST_EXTEND] = "LIST_EXTEND", [SET_UPDATE] = "SET_UPDATE", [DICT_MERGE] = "DICT_MERGE", [DICT_UPDATE] = "DICT_UPDATE", + [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE", + [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT", + [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT", [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST", [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST", - [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", - [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", - [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [CALL] = "CALL", [KW_NAMES] = "KW_NAMES", [POP_JUMP_BACKWARD_IF_NOT_NONE] = "POP_JUMP_BACKWARD_IF_NOT_NONE", [POP_JUMP_BACKWARD_IF_NONE] = "POP_JUMP_BACKWARD_IF_NONE", [POP_JUMP_BACKWARD_IF_FALSE] = "POP_JUMP_BACKWARD_IF_FALSE", [POP_JUMP_BACKWARD_IF_TRUE] = "POP_JUMP_BACKWARD_IF_TRUE", + [STORE_SUBSCR_ADAPTIVE] = "STORE_SUBSCR_ADAPTIVE", + [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT", + [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT", [UNPACK_SEQUENCE_ADAPTIVE] = "UNPACK_SEQUENCE_ADAPTIVE", [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST", [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE", [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE", - [181] = "<181>", - [182] = "<182>", - [183] = "<183>", [184] = "<184>", [185] = "<185>", [186] = "<186>", @@ -684,9 +690,6 @@ static const char *const _PyOpcode_OpName[256] = { #endif #define EXTRA_CASES \ - case 181: \ - case 182: \ - case 183: \ case 184: \ case 185: \ case 186: \ diff --git a/Include/internal/pycore_tuple.h b/Include/internal/pycore_tuple.h index 1efe4fa2bdef94..76451d702f2819 100644 --- a/Include/internal/pycore_tuple.h +++ b/Include/internal/pycore_tuple.h @@ -67,6 +67,12 @@ struct _Py_tuple_state { extern PyObject *_PyTuple_FromArray(PyObject *const *, Py_ssize_t); extern PyObject *_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t); +typedef struct { + PyObject_HEAD + Py_ssize_t it_index; + PyTupleObject *it_seq; /* Set to NULL when iterator is exhausted */ +} _PyTupleIterObject; + #ifdef __cplusplus } #endif diff --git a/Include/opcode.h b/Include/opcode.h index 7a22d5257a669b..74b6b9692f685e 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -158,38 +158,41 @@ extern "C" { #define FOR_ITER_ADAPTIVE 59 #define FOR_ITER_LIST 62 #define FOR_ITER_RANGE 63 -#define JUMP_BACKWARD_QUICK 64 -#define LOAD_ATTR_ADAPTIVE 65 -#define LOAD_ATTR_CLASS 66 -#define LOAD_ATTR_INSTANCE_VALUE 67 -#define LOAD_ATTR_MODULE 72 -#define LOAD_ATTR_PROPERTY 73 -#define LOAD_ATTR_SLOT 76 -#define LOAD_ATTR_WITH_HINT 77 -#define LOAD_ATTR_METHOD_LAZY_DICT 78 -#define LOAD_ATTR_METHOD_NO_DICT 79 -#define LOAD_ATTR_METHOD_WITH_DICT 80 -#define LOAD_ATTR_METHOD_WITH_VALUES 81 -#define LOAD_CONST__LOAD_FAST 86 -#define LOAD_FAST__LOAD_CONST 113 -#define LOAD_FAST__LOAD_FAST 121 -#define LOAD_GLOBAL_ADAPTIVE 141 -#define LOAD_GLOBAL_BUILTIN 143 -#define LOAD_GLOBAL_MODULE 153 -#define RESUME_QUICK 154 -#define STORE_ATTR_ADAPTIVE 158 -#define STORE_ATTR_INSTANCE_VALUE 159 -#define STORE_ATTR_SLOT 160 -#define STORE_ATTR_WITH_HINT 161 -#define STORE_FAST__LOAD_FAST 166 -#define STORE_FAST__STORE_FAST 167 -#define STORE_SUBSCR_ADAPTIVE 168 -#define STORE_SUBSCR_DICT 169 -#define STORE_SUBSCR_LIST_INT 170 -#define UNPACK_SEQUENCE_ADAPTIVE 177 -#define UNPACK_SEQUENCE_LIST 178 -#define UNPACK_SEQUENCE_TUPLE 179 -#define UNPACK_SEQUENCE_TWO_TUPLE 180 +#define FOR_ITER_TUPLE 64 +#define FOR_ITER_DICT_ITEMS 65 +#define FOR_ITER_ENUMERATE 66 +#define JUMP_BACKWARD_QUICK 67 +#define LOAD_ATTR_ADAPTIVE 72 +#define LOAD_ATTR_CLASS 73 +#define LOAD_ATTR_INSTANCE_VALUE 76 +#define LOAD_ATTR_MODULE 77 +#define LOAD_ATTR_PROPERTY 78 +#define LOAD_ATTR_SLOT 79 +#define LOAD_ATTR_WITH_HINT 80 +#define LOAD_ATTR_METHOD_LAZY_DICT 81 +#define LOAD_ATTR_METHOD_NO_DICT 86 +#define LOAD_ATTR_METHOD_WITH_DICT 113 +#define LOAD_ATTR_METHOD_WITH_VALUES 121 +#define LOAD_CONST__LOAD_FAST 141 +#define LOAD_FAST__LOAD_CONST 143 +#define LOAD_FAST__LOAD_FAST 153 +#define LOAD_GLOBAL_ADAPTIVE 154 +#define LOAD_GLOBAL_BUILTIN 158 +#define LOAD_GLOBAL_MODULE 159 +#define RESUME_QUICK 160 +#define STORE_ATTR_ADAPTIVE 161 +#define STORE_ATTR_INSTANCE_VALUE 166 +#define STORE_ATTR_SLOT 167 +#define STORE_ATTR_WITH_HINT 168 +#define STORE_FAST__LOAD_FAST 169 +#define STORE_FAST__STORE_FAST 170 +#define STORE_SUBSCR_ADAPTIVE 177 +#define STORE_SUBSCR_DICT 178 +#define STORE_SUBSCR_LIST_INT 179 +#define UNPACK_SEQUENCE_ADAPTIVE 180 +#define UNPACK_SEQUENCE_LIST 181 +#define UNPACK_SEQUENCE_TUPLE 182 +#define UNPACK_SEQUENCE_TWO_TUPLE 183 #define DO_TRACING 255 #define HAS_CONST(op) (false\ diff --git a/Lib/opcode.py b/Lib/opcode.py index f515aaa9fc8ddc..d3c84a36a897e8 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -282,6 +282,9 @@ def jabs_op(name, op): "FOR_ITER_ADAPTIVE", "FOR_ITER_LIST", "FOR_ITER_RANGE", + "FOR_ITER_TUPLE", + "FOR_ITER_DICT_ITEMS", + "FOR_ITER_ENUMERATE", ], "JUMP_BACKWARD": [ "JUMP_BACKWARD_QUICK", diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index dfb8597b876e5c..3364fee5e4079d 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -1013,14 +1013,8 @@ _PyTuple_ClearFreeList(PyInterpreterState *interp) /*********************** Tuple Iterator **************************/ -typedef struct { - PyObject_HEAD - Py_ssize_t it_index; - PyTupleObject *it_seq; /* Set to NULL when iterator is exhausted */ -} tupleiterobject; - static void -tupleiter_dealloc(tupleiterobject *it) +tupleiter_dealloc(_PyTupleIterObject *it) { _PyObject_GC_UNTRACK(it); Py_XDECREF(it->it_seq); @@ -1028,14 +1022,14 @@ tupleiter_dealloc(tupleiterobject *it) } static int -tupleiter_traverse(tupleiterobject *it, visitproc visit, void *arg) +tupleiter_traverse(_PyTupleIterObject *it, visitproc visit, void *arg) { Py_VISIT(it->it_seq); return 0; } static PyObject * -tupleiter_next(tupleiterobject *it) +tupleiter_next(_PyTupleIterObject *it) { PyTupleObject *seq; PyObject *item; @@ -1059,7 +1053,7 @@ tupleiter_next(tupleiterobject *it) } static PyObject * -tupleiter_len(tupleiterobject *it, PyObject *Py_UNUSED(ignored)) +tupleiter_len(_PyTupleIterObject *it, PyObject *Py_UNUSED(ignored)) { Py_ssize_t len = 0; if (it->it_seq) @@ -1070,7 +1064,7 @@ tupleiter_len(tupleiterobject *it, PyObject *Py_UNUSED(ignored)) PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); static PyObject * -tupleiter_reduce(tupleiterobject *it, PyObject *Py_UNUSED(ignored)) +tupleiter_reduce(_PyTupleIterObject *it, PyObject *Py_UNUSED(ignored)) { if (it->it_seq) return Py_BuildValue("N(O)n", _PyEval_GetBuiltin(&_Py_ID(iter)), @@ -1080,7 +1074,7 @@ tupleiter_reduce(tupleiterobject *it, PyObject *Py_UNUSED(ignored)) } static PyObject * -tupleiter_setstate(tupleiterobject *it, PyObject *state) +tupleiter_setstate(_PyTupleIterObject *it, PyObject *state) { Py_ssize_t index = PyLong_AsSsize_t(state); if (index == -1 && PyErr_Occurred()) @@ -1108,7 +1102,7 @@ static PyMethodDef tupleiter_methods[] = { PyTypeObject PyTupleIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "tuple_iterator", /* tp_name */ - sizeof(tupleiterobject), /* tp_basicsize */ + sizeof(_PyTupleIterObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)tupleiter_dealloc, /* tp_dealloc */ @@ -1141,13 +1135,13 @@ PyTypeObject PyTupleIter_Type = { static PyObject * tuple_iter(PyObject *seq) { - tupleiterobject *it; + _PyTupleIterObject *it; if (!PyTuple_Check(seq)) { PyErr_BadInternalCall(); return NULL; } - it = PyObject_GC_New(tupleiterobject, &PyTupleIter_Type); + it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); if (it == NULL) return NULL; it->it_index = 0; diff --git a/Python/ceval.c b/Python/ceval.c index 47dd1008c35ced..77de4e3b0b1d54 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4488,6 +4488,35 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int goto iterator_exhausted_no_error; } + TARGET(FOR_ITER_TUPLE) { + assert(cframe.use_tracing == 0); + _PyTupleIterObject *it = (_PyTupleIterObject *)TOP(); + DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); + STAT_INC(FOR_ITER, hit); + PyTupleObject *seq = it->it_seq; + if (seq == NULL) { + goto iterator_exhausted_no_error; + } + if (it->it_index < PyTuple_GET_SIZE(seq)) { + PyObject *next = PyTuple_GET_ITEM(seq, it->it_index++); + Py_INCREF(next); + PUSH(next); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + NOTRACE_DISPATCH(); + } + it->it_seq = NULL; + Py_DECREF(seq); + goto iterator_exhausted_no_error; + } + + TARGET(FOR_ITER_DICT_ITEMS) { + Py_UNREACHABLE(); + } + + TARGET(FOR_ITER_ENUMERATE) { + Py_UNREACHABLE(); + } + TARGET(FOR_ITER_RANGE) { assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)TOP(); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 8a6f1cdbbbb62f..3d847df212024b 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -63,29 +63,29 @@ static void *opcode_targets[256] = { &&TARGET_DELETE_SUBSCR, &&TARGET_FOR_ITER_LIST, &&TARGET_FOR_ITER_RANGE, + &&TARGET_FOR_ITER_TUPLE, + &&TARGET_FOR_ITER_DICT_ITEMS, + &&TARGET_FOR_ITER_ENUMERATE, &&TARGET_JUMP_BACKWARD_QUICK, - &&TARGET_LOAD_ATTR_ADAPTIVE, - &&TARGET_LOAD_ATTR_CLASS, - &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_LOAD_ATTR_MODULE, - &&TARGET_LOAD_ATTR_PROPERTY, + &&TARGET_LOAD_ATTR_ADAPTIVE, + &&TARGET_LOAD_ATTR_CLASS, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_ATTR_INSTANCE_VALUE, + &&TARGET_LOAD_ATTR_MODULE, + &&TARGET_LOAD_ATTR_PROPERTY, &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_METHOD_LAZY_DICT, - &&TARGET_LOAD_ATTR_METHOD_NO_DICT, - &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, - &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, &&TARGET_SETUP_ANNOTATIONS, - &&TARGET_LOAD_CONST__LOAD_FAST, + &&TARGET_LOAD_ATTR_METHOD_NO_DICT, &&TARGET_ASYNC_GEN_WRAP, &&TARGET_PREP_RERAISE_STAR, &&TARGET_POP_EXCEPT, @@ -112,7 +112,7 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_FORWARD, &&TARGET_JUMP_IF_FALSE_OR_POP, &&TARGET_JUMP_IF_TRUE_OR_POP, - &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_LOAD_ATTR_METHOD_WITH_DICT, &&TARGET_POP_JUMP_FORWARD_IF_FALSE, &&TARGET_POP_JUMP_FORWARD_IF_TRUE, &&TARGET_LOAD_GLOBAL, @@ -120,7 +120,7 @@ static void *opcode_targets[256] = { &&TARGET_CONTAINS_OP, &&TARGET_RERAISE, &&TARGET_COPY, - &&TARGET_LOAD_FAST__LOAD_FAST, + &&TARGET_LOAD_ATTR_METHOD_WITH_VALUES, &&TARGET_BINARY_OP, &&TARGET_SEND, &&TARGET_LOAD_FAST, @@ -140,9 +140,9 @@ static void *opcode_targets[256] = { &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, &&TARGET_JUMP_BACKWARD, - &&TARGET_LOAD_GLOBAL_ADAPTIVE, + &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, @@ -152,30 +152,33 @@ static void *opcode_targets[256] = { &&TARGET_YIELD_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_RESUME_QUICK, + &&TARGET_LOAD_FAST__LOAD_FAST, + &&TARGET_LOAD_GLOBAL_ADAPTIVE, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_LOAD_GLOBAL_BUILTIN, + &&TARGET_LOAD_GLOBAL_MODULE, + &&TARGET_RESUME_QUICK, &&TARGET_STORE_ATTR_ADAPTIVE, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, - &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_SLOT, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, - &&TARGET_STORE_SUBSCR_ADAPTIVE, - &&TARGET_STORE_SUBSCR_DICT, - &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_POP_JUMP_BACKWARD_IF_NOT_NONE, &&TARGET_POP_JUMP_BACKWARD_IF_NONE, &&TARGET_POP_JUMP_BACKWARD_IF_FALSE, &&TARGET_POP_JUMP_BACKWARD_IF_TRUE, + &&TARGET_STORE_SUBSCR_ADAPTIVE, + &&TARGET_STORE_SUBSCR_DICT, + &&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_UNPACK_SEQUENCE_ADAPTIVE, &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, @@ -251,8 +254,5 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_DO_TRACING }; diff --git a/Python/specialize.c b/Python/specialize.c index 948fb328695bb9..5911378237fcc6 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2120,6 +2120,10 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr) _Py_SET_OPCODE(*instr, FOR_ITER_LIST); goto success; } + if (tp == &PyTupleIter_Type) { + _Py_SET_OPCODE(*instr, FOR_ITER_TUPLE); + goto success; + } else if (tp == &PyRangeIter_Type && next_op == STORE_FAST) { _Py_SET_OPCODE(*instr, FOR_ITER_RANGE); goto success; From 7b8c26aa69edd51ae27292733f852a76c553e1e6 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Tue, 21 Jun 2022 15:36:43 -0400 Subject: [PATCH 2/5] get dict items working --- Include/internal/pycore_dict.h | 11 +++ Objects/dictobject.c | 120 ++++++++++++++++++--------------- Python/ceval.c | 21 +++++- Python/specialize.c | 10 ++- 4 files changed, 105 insertions(+), 57 deletions(-) diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index c831c4ccbd0cb6..f9cb9bdf85a833 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -183,6 +183,17 @@ _PyDictValues_AddToInsertionOrder(PyDictValues *values, Py_ssize_t ix) *size_ptr = size; } +typedef struct { + PyObject_HEAD + PyDictObject *di_dict; /* Set to NULL when iterator is exhausted */ + Py_ssize_t di_used; + Py_ssize_t di_pos; + PyObject* di_result; /* reusable result tuple for iteritems */ + Py_ssize_t len; +} _PyDictIterObject; + +extern int _PyDictItemsIter_GetNext(_PyDictIterObject *, PyObject **); + #ifdef __cplusplus } #endif diff --git a/Objects/dictobject.c b/Objects/dictobject.c index ebbd22ee7c145e..6a2f9fee163e0c 100644 --- a/Objects/dictobject.c +++ b/Objects/dictobject.c @@ -3946,20 +3946,11 @@ PyDict_DelItemString(PyObject *v, const char *key) /* Dictionary iterator types */ -typedef struct { - PyObject_HEAD - PyDictObject *di_dict; /* Set to NULL when iterator is exhausted */ - Py_ssize_t di_used; - Py_ssize_t di_pos; - PyObject* di_result; /* reusable result tuple for iteritems */ - Py_ssize_t len; -} dictiterobject; - static PyObject * dictiter_new(PyDictObject *dict, PyTypeObject *itertype) { - dictiterobject *di; - di = PyObject_GC_New(dictiterobject, itertype); + _PyDictIterObject *di; + di = PyObject_GC_New(_PyDictIterObject, itertype); if (di == NULL) { return NULL; } @@ -3996,7 +3987,7 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype) } static void -dictiter_dealloc(dictiterobject *di) +dictiter_dealloc(_PyDictIterObject *di) { /* bpo-31095: UnTrack is needed before calling any callbacks */ _PyObject_GC_UNTRACK(di); @@ -4006,7 +3997,7 @@ dictiter_dealloc(dictiterobject *di) } static int -dictiter_traverse(dictiterobject *di, visitproc visit, void *arg) +dictiter_traverse(_PyDictIterObject *di, visitproc visit, void *arg) { Py_VISIT(di->di_dict); Py_VISIT(di->di_result); @@ -4014,7 +4005,7 @@ dictiter_traverse(dictiterobject *di, visitproc visit, void *arg) } static PyObject * -dictiter_len(dictiterobject *di, PyObject *Py_UNUSED(ignored)) +dictiter_len(_PyDictIterObject *di, PyObject *Py_UNUSED(ignored)) { Py_ssize_t len = 0; if (di->di_dict != NULL && di->di_used == di->di_dict->ma_used) @@ -4026,7 +4017,7 @@ PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); static PyObject * -dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored)); +dictiter_reduce(_PyDictIterObject *di, PyObject *Py_UNUSED(ignored)); PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); @@ -4039,7 +4030,7 @@ static PyMethodDef dictiter_methods[] = { }; static PyObject* -dictiter_iternextkey(dictiterobject *di) +dictiter_iternextkey(_PyDictIterObject *di) { PyObject *key; Py_ssize_t i; @@ -4110,7 +4101,7 @@ dictiter_iternextkey(dictiterobject *di) PyTypeObject PyDictIterKey_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "dict_keyiterator", /* tp_name */ - sizeof(dictiterobject), /* tp_basicsize */ + sizeof(_PyDictIterObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)dictiter_dealloc, /* tp_dealloc */ @@ -4141,7 +4132,7 @@ PyTypeObject PyDictIterKey_Type = { }; static PyObject * -dictiter_iternextvalue(dictiterobject *di) +dictiter_iternextvalue(_PyDictIterObject *di) { PyObject *value; Py_ssize_t i; @@ -4210,7 +4201,7 @@ dictiter_iternextvalue(dictiterobject *di) PyTypeObject PyDictIterValue_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "dict_valueiterator", /* tp_name */ - sizeof(dictiterobject), /* tp_basicsize */ + sizeof(_PyDictIterObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)dictiter_dealloc, /* tp_dealloc */ @@ -4240,33 +4231,35 @@ PyTypeObject PyDictIterValue_Type = { 0, }; -static PyObject * -dictiter_iternextitem(dictiterobject *di) +/* Do stack += [value, key] + returns 1 on success, 0 on StopIteration, -1 on error. */ +int +_PyDictItemsIter_GetNext(_PyDictIterObject *di, PyObject **stack) { - PyObject *key, *value, *result; + assert(Py_IS_TYPE((PyObject *)di, &PyDictIterItem_Type)); Py_ssize_t i; PyDictObject *d = di->di_dict; if (d == NULL) - return NULL; + return 0; assert (PyDict_Check(d)); if (di->di_used != d->ma_used) { PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); di->di_used = -1; /* Make this state sticky */ - return NULL; + return -1; } i = di->di_pos; assert(i >= 0); if (d->ma_values) { if (i >= d->ma_used) - goto fail; + goto exhausted; int index = get_index_from_order(d, i); - key = DK_UNICODE_ENTRIES(d->ma_keys)[index].me_key; - value = d->ma_values->values[index]; - assert(value != NULL); + stack[1] = DK_UNICODE_ENTRIES(d->ma_keys)[index].me_key; + stack[0] = d->ma_values->values[index]; + assert(stack[0] != NULL); } else { Py_ssize_t n = d->ma_keys->dk_nentries; @@ -4277,9 +4270,9 @@ dictiter_iternextitem(dictiterobject *di) i++; } if (i >= n) - goto fail; - key = entry_ptr->me_key; - value = entry_ptr->me_value; + goto exhausted; + stack[1] = entry_ptr->me_key; + stack[0] = entry_ptr->me_value; } else { PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i]; @@ -4288,9 +4281,9 @@ dictiter_iternextitem(dictiterobject *di) i++; } if (i >= n) - goto fail; - key = entry_ptr->me_key; - value = entry_ptr->me_value; + goto exhausted; + stack[1] = entry_ptr->me_key; + stack[0] = entry_ptr->me_value; } } // We found an element, but did not expect it @@ -4301,14 +4294,34 @@ dictiter_iternextitem(dictiterobject *di) } di->di_pos = i+1; di->len--; - Py_INCREF(key); - Py_INCREF(value); - result = di->di_result; + Py_INCREF(stack[0]); + Py_INCREF(stack[1]); + return 1; +exhausted: + di->di_dict = NULL; + Py_DECREF(d); + return 0; +fail: + di->di_dict = NULL; + Py_DECREF(d); + return -1; +} + + +static PyObject * +dictiter_iternextitem(_PyDictIterObject *di) +{ + PyObject *stack[2]; + int err = _PyDictItemsIter_GetNext(di, stack); + if (err <= 0) { + return NULL; + } + PyObject *result = di->di_result; if (Py_REFCNT(result) == 1) { PyObject *oldkey = PyTuple_GET_ITEM(result, 0); PyObject *oldvalue = PyTuple_GET_ITEM(result, 1); - PyTuple_SET_ITEM(result, 0, key); /* steals reference */ - PyTuple_SET_ITEM(result, 1, value); /* steals reference */ + PyTuple_SET_ITEM(result, 0, stack[1]); /* steals reference */ + PyTuple_SET_ITEM(result, 1, stack[0]); /* steals reference */ Py_INCREF(result); Py_DECREF(oldkey); Py_DECREF(oldvalue); @@ -4320,23 +4333,22 @@ dictiter_iternextitem(dictiterobject *di) } else { result = PyTuple_New(2); - if (result == NULL) + if (result == NULL) { + Py_DECREF(stack[0]); + Py_DECREF(stack[1]); return NULL; - PyTuple_SET_ITEM(result, 0, key); /* steals reference */ - PyTuple_SET_ITEM(result, 1, value); /* steals reference */ + } + PyTuple_SET_ITEM(result, 0, stack[1]); /* steals reference */ + PyTuple_SET_ITEM(result, 1, stack[0]); /* steals reference */ } return result; - -fail: - di->di_dict = NULL; - Py_DECREF(d); - return NULL; } + PyTypeObject PyDictIterItem_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "dict_itemiterator", /* tp_name */ - sizeof(dictiterobject), /* tp_basicsize */ + sizeof(_PyDictIterObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)dictiter_dealloc, /* tp_dealloc */ @@ -4370,7 +4382,7 @@ PyTypeObject PyDictIterItem_Type = { /* dictreviter */ static PyObject * -dictreviter_iternext(dictiterobject *di) +dictreviter_iternext(_PyDictIterObject *di) { PyDictObject *d = di->di_dict; @@ -4475,7 +4487,7 @@ dictreviter_iternext(dictiterobject *di) PyTypeObject PyDictRevIterKey_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "dict_reversekeyiterator", - sizeof(dictiterobject), + sizeof(_PyDictIterObject), .tp_dealloc = (destructor)dictiter_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)dictiter_traverse, @@ -4500,10 +4512,10 @@ dict___reversed___impl(PyDictObject *self) } static PyObject * -dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored)) +dictiter_reduce(_PyDictIterObject *di, PyObject *Py_UNUSED(ignored)) { /* copy the iterator state */ - dictiterobject tmp = *di; + _PyDictIterObject tmp = *di; Py_XINCREF(tmp.di_dict); PyObject *list = PySequence_List((PyObject*)&tmp); @@ -4517,7 +4529,7 @@ dictiter_reduce(dictiterobject *di, PyObject *Py_UNUSED(ignored)) PyTypeObject PyDictRevIterItem_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "dict_reverseitemiterator", - sizeof(dictiterobject), + sizeof(_PyDictIterObject), .tp_dealloc = (destructor)dictiter_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)dictiter_traverse, @@ -4529,7 +4541,7 @@ PyTypeObject PyDictRevIterItem_Type = { PyTypeObject PyDictRevIterValue_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "dict_reversevalueiterator", - sizeof(dictiterobject), + sizeof(_PyDictIterObject), .tp_dealloc = (destructor)dictiter_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)dictiter_traverse, diff --git a/Python/ceval.c b/Python/ceval.c index 77de4e3b0b1d54..330c62d38db888 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4510,7 +4510,26 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(FOR_ITER_DICT_ITEMS) { - Py_UNREACHABLE(); + assert(cframe.use_tracing == 0); + _PyDictIterObject *it = (_PyDictIterObject *)TOP(); + DEOPT_IF(Py_TYPE(it) != &PyDictIterItem_Type, FOR_ITER); + _Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER]; + assert(_PyOpcode_Deopt[_Py_OPCODE(next)] == UNPACK_SEQUENCE); + assert(_Py_OPARG(next) == 2); + int res = _PyDictItemsIter_GetNext(it, stack_pointer); + if (res > 0) { + STACK_GROW(2); + assert(TOP() != NULL && SECOND() != NULL); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1 + + INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); + NOTRACE_DISPATCH(); + } + else if (res == 0) { + goto iterator_exhausted_no_error; + } + else { + goto error; + } } TARGET(FOR_ITER_ENUMERATE) { diff --git a/Python/specialize.c b/Python/specialize.c index 5911378237fcc6..46812685276adc 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2115,7 +2115,8 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr) _PyForIterCache *cache = (_PyForIterCache *)(instr + 1); PyTypeObject *tp = Py_TYPE(iter); _Py_CODEUNIT next = instr[1+INLINE_CACHE_ENTRIES_FOR_ITER]; - int next_op = _PyOpcode_Deopt[_Py_OPCODE(next)]; + int next_opcode = _PyOpcode_Deopt[_Py_OPCODE(next)]; + int next_oparg = _Py_OPARG(next); if (tp == &PyListIter_Type) { _Py_SET_OPCODE(*instr, FOR_ITER_LIST); goto success; @@ -2124,10 +2125,15 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr) _Py_SET_OPCODE(*instr, FOR_ITER_TUPLE); goto success; } - else if (tp == &PyRangeIter_Type && next_op == STORE_FAST) { + else if (tp == &PyRangeIter_Type && next_opcode == STORE_FAST) { _Py_SET_OPCODE(*instr, FOR_ITER_RANGE); goto success; } + else if (tp == &PyDictIterItem_Type && next_opcode == UNPACK_SEQUENCE + && next_oparg == 2) { + _Py_SET_OPCODE(*instr, FOR_ITER_DICT_ITEMS); + goto success; + } else { SPECIALIZATION_FAIL(FOR_ITER, _PySpecialization_ClassifyIterator(iter)); From 13195295ae7b3186d111a7bb1fb672e54d4dcaa5 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Tue, 21 Jun 2022 16:47:10 -0400 Subject: [PATCH 3/5] get enumerate working --- Include/internal/pycore_dict.h | 2 +- Makefile.pre.in | 1 + Objects/enumobject.c | 52 ++++++++++++++++++++---------- PCbuild/pythoncore.vcxproj | 1 + PCbuild/pythoncore.vcxproj.filters | 3 ++ Python/ceval.c | 23 ++++++++++++- Python/specialize.c | 9 ++++++ 7 files changed, 72 insertions(+), 19 deletions(-) diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h index f9cb9bdf85a833..655d1c297bc0ec 100644 --- a/Include/internal/pycore_dict.h +++ b/Include/internal/pycore_dict.h @@ -192,7 +192,7 @@ typedef struct { Py_ssize_t len; } _PyDictIterObject; -extern int _PyDictItemsIter_GetNext(_PyDictIterObject *, PyObject **); +int _PyDictItemsIter_GetNext(_PyDictIterObject *, PyObject **); #ifdef __cplusplus } diff --git a/Makefile.pre.in b/Makefile.pre.in index 6448785c28070e..c2895a6823d760 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1601,6 +1601,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/internal/pycore_dict.h \ $(srcdir)/Include/internal/pycore_descrobject.h \ $(srcdir)/Include/internal/pycore_dtoa.h \ + $(srcdir)/Include/internal/pycore_enumerate.h \ $(srcdir)/Include/internal/pycore_exceptions.h \ $(srcdir)/Include/internal/pycore_fileutils.h \ $(srcdir)/Include/internal/pycore_floatobject.h \ diff --git a/Objects/enumobject.c b/Objects/enumobject.c index d84bac6f4c9af2..1baefaa15d541e 100644 --- a/Objects/enumobject.c +++ b/Objects/enumobject.c @@ -4,6 +4,7 @@ #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_long.h" // _PyLong_GetOne() #include "pycore_object.h" // _PyObject_GC_TRACK() +#include "pycore_enumerate.h" // _PyEnumObject #include "clinic/enumobject.c.h" @@ -13,15 +14,6 @@ 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 */ - PyObject* en_sit; /* secondary iterator of enumeration */ - PyObject* en_result; /* result tuple */ - PyObject* en_longindex; /* index for sequences >= PY_SSIZE_T_MAX */ - PyObject* one; /* borrowed reference */ -} enumobject; - /*[clinic input] @classmethod @@ -44,9 +36,9 @@ static PyObject * enum_new_impl(PyTypeObject *type, PyObject *iterable, PyObject *start) /*[clinic end generated code: output=e95e6e439f812c10 input=782e4911efcb8acf]*/ { - enumobject *en; + _PyEnumObject *en; - en = (enumobject *)type->tp_alloc(type, 0); + en = (_PyEnumObject *)type->tp_alloc(type, 0); if (en == NULL) return NULL; if (start != NULL) { @@ -149,7 +141,7 @@ enumerate_vectorcall(PyObject *type, PyObject *const *args, } static void -enum_dealloc(enumobject *en) +enum_dealloc(_PyEnumObject *en) { PyObject_GC_UnTrack(en); Py_XDECREF(en->en_sit); @@ -159,7 +151,7 @@ enum_dealloc(enumobject *en) } static int -enum_traverse(enumobject *en, visitproc visit, void *arg) +enum_traverse(_PyEnumObject *en, visitproc visit, void *arg) { Py_VISIT(en->en_sit); Py_VISIT(en->en_result); @@ -168,7 +160,7 @@ enum_traverse(enumobject *en, visitproc visit, void *arg) } static PyObject * -enum_next_long(enumobject *en, PyObject* next_item) +enum_next_long(_PyEnumObject *en, PyObject* next_item) { PyObject *result = en->en_result; PyObject *next_index; @@ -218,8 +210,34 @@ enum_next_long(enumobject *en, PyObject* next_item) return result; } +int +_PyEnum_GetNext(_PyEnumObject *en, PyObject **stack, PyObject **index_target) +{ + PyObject *it = en->en_sit; + stack[0] = (*Py_TYPE(it)->tp_iternext)(it); + if (stack[0] == NULL) { + return -1; + } + if (en->en_index == PY_SSIZE_T_MAX) { + PyObject *pair = enum_next_long(en, stack[0]); + if (pair == NULL) { + Py_DECREF(stack[0]); + return -1; + } + *index_target = PyTuple_GET_ITEM(pair, 0); + Py_DECREF(pair); + return 0; + } + if (_PyLong_AssignValue(index_target, en->en_index) < 0) { + Py_DECREF(stack[0]); + return -1; + } + en->en_index++; + return 0; +} + static PyObject * -enum_next(enumobject *en) +enum_next(_PyEnumObject *en) { PyObject *next_index; PyObject *next_item; @@ -269,7 +287,7 @@ enum_next(enumobject *en) } static PyObject * -enum_reduce(enumobject *en, PyObject *Py_UNUSED(ignored)) +enum_reduce(_PyEnumObject *en, PyObject *Py_UNUSED(ignored)) { if (en->en_longindex != NULL) return Py_BuildValue("O(OO)", Py_TYPE(en), en->en_sit, en->en_longindex); @@ -289,7 +307,7 @@ static PyMethodDef enum_methods[] = { PyTypeObject PyEnum_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "enumerate", /* tp_name */ - sizeof(enumobject), /* tp_basicsize */ + sizeof(_PyEnumObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)enum_dealloc, /* tp_dealloc */ diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 09acce9d0c894a..a0663f22d6ccb3 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -210,6 +210,7 @@ + diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 4d91a7ad0b3e75..2b0ce6c9d91e94 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -537,6 +537,9 @@ Include\internal + + Include\internal + Include\internal diff --git a/Python/ceval.c b/Python/ceval.c index 330c62d38db888..7909a4c40f3cbd 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -26,6 +26,7 @@ #include "pycore_sysmodule.h" // _PySys_Audit() #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS +#include "pycore_enumerate.h" #include "pycore_dict.h" #include "dictobject.h" @@ -4435,6 +4436,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); DISPATCH(); } + iterator_exhausted: if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { goto error; @@ -4533,7 +4535,26 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(FOR_ITER_ENUMERATE) { - Py_UNREACHABLE(); + // FOR_ITER + UNPACK_SEQUENCE(2) + STORE_FAST + assert(cframe.use_tracing == 0); + _PyEnumObject *it = (_PyEnumObject *)TOP(); + DEOPT_IF(Py_TYPE(it) != &PyEnum_Type, FOR_ITER); + _Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER]; + assert(_PyOpcode_Deopt[_Py_OPCODE(next)] == UNPACK_SEQUENCE); + assert(_Py_OPARG(next) == 2); + _Py_CODEUNIT nextnext = + next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + + 1 + INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE]; + assert(_PyOpcode_Deopt[_Py_OPCODE(nextnext)] == STORE_FAST); + PyObject **target = &GETLOCAL(_Py_OPARG(nextnext)); + int err = _PyEnum_GetNext(it, stack_pointer, target); + if (err < 0) { + goto iterator_exhausted; + } + STACK_GROW(1); + JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1 + + INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE + 1); + DISPATCH(); } TARGET(FOR_ITER_RANGE) { diff --git a/Python/specialize.c b/Python/specialize.c index 46812685276adc..38c107b38a9ba4 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -2117,6 +2117,9 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr) _Py_CODEUNIT next = instr[1+INLINE_CACHE_ENTRIES_FOR_ITER]; int next_opcode = _PyOpcode_Deopt[_Py_OPCODE(next)]; int next_oparg = _Py_OPARG(next); + _Py_CODEUNIT nextnext = instr[1 + INLINE_CACHE_ENTRIES_FOR_ITER + + 1 + INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE]; + int nextnext_opcode = _PyOpcode_Deopt[_Py_OPCODE(nextnext)]; if (tp == &PyListIter_Type) { _Py_SET_OPCODE(*instr, FOR_ITER_LIST); goto success; @@ -2134,6 +2137,12 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr) _Py_SET_OPCODE(*instr, FOR_ITER_DICT_ITEMS); goto success; } + else if (tp == &PyEnum_Type && + next_opcode == UNPACK_SEQUENCE && next_oparg == 2 && + nextnext_opcode == STORE_FAST) { + _Py_SET_OPCODE(*instr, FOR_ITER_ENUMERATE); + goto success; + } else { SPECIALIZATION_FAIL(FOR_ITER, _PySpecialization_ClassifyIterator(iter)); From 1c421c0189635b0e6448f7d763cb64deaccac6ca Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Tue, 21 Jun 2022 17:38:06 -0400 Subject: [PATCH 4/5] git add the new file --- Include/internal/pycore_enumerate.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Include/internal/pycore_enumerate.h diff --git a/Include/internal/pycore_enumerate.h b/Include/internal/pycore_enumerate.h new file mode 100644 index 00000000000000..1bf333283aca18 --- /dev/null +++ b/Include/internal/pycore_enumerate.h @@ -0,0 +1,26 @@ +#ifndef Py_INTERNAL_ENUMERATE_H +#define Py_INTERNAL_ENUMERATE_H +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef Py_BUILD_CORE +# error "this header requires Py_BUILD_CORE define" +#endif + +typedef struct { + PyObject_HEAD + Py_ssize_t en_index; /* current index of enumeration */ + PyObject* en_sit; /* secondary iterator of enumeration */ + PyObject* en_result; /* result tuple */ + PyObject* en_longindex; /* index for sequences >= PY_SSIZE_T_MAX */ + PyObject* one; /* borrowed reference */ +} _PyEnumObject; + +int +_PyEnum_GetNext(_PyEnumObject *en, PyObject **stack, PyObject **index_target); + +#ifdef __cplusplus +} +#endif +#endif /* !Py_INTERNAL_ENUMERATE_H */ From 11da11010b8a9065940a173851e9a5fff8510264 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Tue, 21 Jun 2022 18:05:02 -0400 Subject: [PATCH 5/5] comments, ifdefs so no unused variable --- Python/ceval.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Python/ceval.c b/Python/ceval.c index 7909a4c40f3cbd..cedc3e21de44b0 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4512,12 +4512,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(FOR_ITER_DICT_ITEMS) { + // FOR_ITER + UNPACK_SEQUENCE(2) assert(cframe.use_tracing == 0); _PyDictIterObject *it = (_PyDictIterObject *)TOP(); DEOPT_IF(Py_TYPE(it) != &PyDictIterItem_Type, FOR_ITER); + #ifndef NDEBUG _Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER]; assert(_PyOpcode_Deopt[_Py_OPCODE(next)] == UNPACK_SEQUENCE); assert(_Py_OPARG(next) == 2); + #endif int res = _PyDictItemsIter_GetNext(it, stack_pointer); if (res > 0) { STACK_GROW(2); @@ -4539,9 +4542,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int assert(cframe.use_tracing == 0); _PyEnumObject *it = (_PyEnumObject *)TOP(); DEOPT_IF(Py_TYPE(it) != &PyEnum_Type, FOR_ITER); + #ifndef NDEBUG _Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER]; assert(_PyOpcode_Deopt[_Py_OPCODE(next)] == UNPACK_SEQUENCE); assert(_Py_OPARG(next) == 2); + #endif _Py_CODEUNIT nextnext = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + 1 + INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE]; @@ -4558,6 +4563,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(FOR_ITER_RANGE) { + // FOR_ITER + STORE_FAST assert(cframe.use_tracing == 0); _PyRangeIterObject *r = (_PyRangeIterObject *)TOP(); DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);