diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h
index c831c4ccbd0cb6..655d1c297bc0ec 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;
+
+int _PyDictItemsIter_GetNext(_PyDictIterObject *, PyObject **);
+
#ifdef __cplusplus
}
#endif
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 */
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/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/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/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/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/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 47dd1008c35ced..cedc3e21de44b0 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;
@@ -4488,7 +4490,80 @@ _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) {
+ // 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);
+ 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) {
+ // 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);
+ #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];
+ 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) {
+ // FOR_ITER + STORE_FAST
assert(cframe.use_tracing == 0);
_PyRangeIterObject *r = (_PyRangeIterObject *)TOP();
DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);
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..38c107b38a9ba4 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -2115,15 +2115,34 @@ _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);
+ _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;
}
- else if (tp == &PyRangeIter_Type && next_op == STORE_FAST) {
+ if (tp == &PyTupleIter_Type) {
+ _Py_SET_OPCODE(*instr, FOR_ITER_TUPLE);
+ goto success;
+ }
+ 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 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));