@@ -2066,27 +2066,35 @@ dummy_func(
2066
2066
PREDICT (LOAD_CONST );
2067
2067
}
2068
2068
2069
- // stack effect: ( -- __0)
2070
- inst (FOR_ITER ) {
2069
+ // Most members of this family are "secretly" super-instructions.
2070
+ // When the loop is exhausted, they jump, and the jump target is
2071
+ // always END_FOR, which pops two values off the stack.
2072
+ // This is optimized by skipping that instruction and combining
2073
+ // its effect (popping 'iter' instead of pushing 'next'.)
2074
+
2075
+ family (for_iter , INLINE_CACHE_ENTRIES_FOR_ITER ) = {
2076
+ FOR_ITER ,
2077
+ FOR_ITER_LIST ,
2078
+ FOR_ITER_TUPLE ,
2079
+ FOR_ITER_RANGE ,
2080
+ FOR_ITER_GEN ,
2081
+ };
2082
+
2083
+ inst (FOR_ITER , (unused /1 , iter -- iter , next )) {
2071
2084
#if ENABLE_SPECIALIZATION
2072
2085
_PyForIterCache * cache = (_PyForIterCache * )next_instr ;
2073
2086
if (ADAPTIVE_COUNTER_IS_ZERO (cache -> counter )) {
2074
2087
assert (cframe .use_tracing == 0 );
2075
2088
next_instr -- ;
2076
- _Py_Specialize_ForIter (TOP () , next_instr , oparg );
2089
+ _Py_Specialize_ForIter (iter , next_instr , oparg );
2077
2090
DISPATCH_SAME_OPARG ();
2078
2091
}
2079
2092
STAT_INC (FOR_ITER , deferred );
2080
2093
DECREMENT_ADAPTIVE_COUNTER (cache -> counter );
2081
2094
#endif /* ENABLE_SPECIALIZATION */
2082
- /* before: [iter]; after: [iter, iter()] *or* [] */
2083
- PyObject * iter = TOP ();
2084
- PyObject * next = (* Py_TYPE (iter )-> tp_iternext )(iter );
2085
- if (next != NULL ) {
2086
- PUSH (next );
2087
- JUMPBY (INLINE_CACHE_ENTRIES_FOR_ITER );
2088
- }
2089
- else {
2095
+ /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */
2096
+ next = (* Py_TYPE (iter )-> tp_iternext )(iter );
2097
+ if (next == NULL ) {
2090
2098
if (_PyErr_Occurred (tstate )) {
2091
2099
if (!_PyErr_ExceptionMatches (tstate , PyExc_StopIteration )) {
2092
2100
goto error ;
@@ -2098,70 +2106,74 @@ dummy_func(
2098
2106
}
2099
2107
/* iterator ended normally */
2100
2108
assert (_Py_OPCODE (next_instr [INLINE_CACHE_ENTRIES_FOR_ITER + oparg ]) == END_FOR );
2101
- STACK_SHRINK (1 );
2102
2109
Py_DECREF (iter );
2103
- /* Skip END_FOR */
2110
+ STACK_SHRINK (1 );
2111
+ /* Jump forward oparg, then skip following END_FOR instruction */
2104
2112
JUMPBY (INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1 );
2113
+ DISPATCH ();
2105
2114
}
2115
+ // Common case: no jump, leave it to the code generator
2106
2116
}
2107
2117
2108
- // stack effect: ( -- __0)
2109
- inst (FOR_ITER_LIST ) {
2118
+ inst (FOR_ITER_LIST , (unused /1 , iter -- iter , next )) {
2110
2119
assert (cframe .use_tracing == 0 );
2111
- _PyListIterObject * it = ( _PyListIterObject * ) TOP ( );
2112
- DEOPT_IF ( Py_TYPE ( it ) != & PyListIter_Type , FOR_ITER ) ;
2120
+ DEOPT_IF ( Py_TYPE ( iter ) != & PyListIter_Type , FOR_ITER );
2121
+ _PyListIterObject * it = ( _PyListIterObject * ) iter ;
2113
2122
STAT_INC (FOR_ITER , hit );
2114
2123
PyListObject * seq = it -> it_seq ;
2115
2124
if (seq ) {
2116
2125
if (it -> it_index < PyList_GET_SIZE (seq )) {
2117
- PyObject * next = PyList_GET_ITEM (seq , it -> it_index ++ );
2118
- PUSH (Py_NewRef (next ));
2119
- JUMPBY (INLINE_CACHE_ENTRIES_FOR_ITER );
2126
+ next = Py_NewRef (PyList_GET_ITEM (seq , it -> it_index ++ ));
2120
2127
goto end_for_iter_list ; // End of this instruction
2121
2128
}
2122
2129
it -> it_seq = NULL ;
2123
2130
Py_DECREF (seq );
2124
2131
}
2132
+ Py_DECREF (iter );
2125
2133
STACK_SHRINK (1 );
2126
- Py_DECREF ( it );
2134
+ /* Jump forward oparg, then skip following END_FOR instruction */
2127
2135
JUMPBY (INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1 );
2136
+ DISPATCH ();
2128
2137
end_for_iter_list :
2138
+ // Common case: no jump, leave it to the code generator
2129
2139
}
2130
2140
2131
- // stack effect: ( -- __0)
2132
- inst (FOR_ITER_TUPLE ) {
2141
+ inst (FOR_ITER_TUPLE , (unused /1 , iter -- iter , next )) {
2133
2142
assert (cframe .use_tracing == 0 );
2134
- _PyTupleIterObject * it = (_PyTupleIterObject * )TOP () ;
2143
+ _PyTupleIterObject * it = (_PyTupleIterObject * )iter ;
2135
2144
DEOPT_IF (Py_TYPE (it ) != & PyTupleIter_Type , FOR_ITER );
2136
2145
STAT_INC (FOR_ITER , hit );
2137
2146
PyTupleObject * seq = it -> it_seq ;
2138
2147
if (seq ) {
2139
2148
if (it -> it_index < PyTuple_GET_SIZE (seq )) {
2140
- PyObject * next = PyTuple_GET_ITEM (seq , it -> it_index ++ );
2141
- PUSH (Py_NewRef (next ));
2142
- JUMPBY (INLINE_CACHE_ENTRIES_FOR_ITER );
2149
+ next = Py_NewRef (PyTuple_GET_ITEM (seq , it -> it_index ++ ));
2143
2150
goto end_for_iter_tuple ; // End of this instruction
2144
2151
}
2145
2152
it -> it_seq = NULL ;
2146
2153
Py_DECREF (seq );
2147
2154
}
2155
+ Py_DECREF (iter );
2148
2156
STACK_SHRINK (1 );
2149
- Py_DECREF ( it );
2157
+ /* Jump forward oparg, then skip following END_FOR instruction */
2150
2158
JUMPBY (INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1 );
2159
+ DISPATCH ();
2151
2160
end_for_iter_tuple :
2161
+ // Common case: no jump, leave it to the code generator
2152
2162
}
2153
2163
2154
- // stack effect: ( -- __0)
2155
- inst (FOR_ITER_RANGE ) {
2164
+ // This is slightly different, when the loop isn't terminated we
2165
+ // jump over the immediately following STORE_FAST instruction.
2166
+ inst (FOR_ITER_RANGE , (unused /1 , iter -- iter , unused )) {
2156
2167
assert (cframe .use_tracing == 0 );
2157
- _PyRangeIterObject * r = (_PyRangeIterObject * )TOP () ;
2168
+ _PyRangeIterObject * r = (_PyRangeIterObject * )iter ;
2158
2169
DEOPT_IF (Py_TYPE (r ) != & PyRangeIter_Type , FOR_ITER );
2159
2170
STAT_INC (FOR_ITER , hit );
2160
2171
_Py_CODEUNIT next = next_instr [INLINE_CACHE_ENTRIES_FOR_ITER ];
2161
2172
assert (_PyOpcode_Deopt [_Py_OPCODE (next )] == STORE_FAST );
2162
2173
if (r -> len <= 0 ) {
2163
2174
STACK_SHRINK (1 );
2164
2175
Py_DECREF (r );
2176
+ // Jump over END_FOR instruction.
2165
2177
JUMPBY (INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1 );
2166
2178
}
2167
2179
else {
@@ -2174,11 +2186,13 @@ dummy_func(
2174
2186
// The STORE_FAST is already done.
2175
2187
JUMPBY (INLINE_CACHE_ENTRIES_FOR_ITER + 1 );
2176
2188
}
2189
+ DISPATCH ();
2177
2190
}
2178
2191
2179
- inst (FOR_ITER_GEN ) {
2192
+ // This is *not* a super-instruction, unique in the family.
2193
+ inst (FOR_ITER_GEN , (unused /1 , iter -- iter , unused )) {
2180
2194
assert (cframe .use_tracing == 0 );
2181
- PyGenObject * gen = (PyGenObject * )TOP () ;
2195
+ PyGenObject * gen = (PyGenObject * )iter ;
2182
2196
DEOPT_IF (Py_TYPE (gen ) != & PyGen_Type , FOR_ITER );
2183
2197
DEOPT_IF (gen -> gi_frame_state >= FRAME_EXECUTING , FOR_ITER );
2184
2198
STAT_INC (FOR_ITER , hit );
@@ -3168,9 +3182,6 @@ family(call, INLINE_CACHE_ENTRIES_CALL) = {
3168
3182
CALL_NO_KW_LIST_APPEND , CALL_NO_KW_METHOD_DESCRIPTOR_FAST , CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS ,
3169
3183
CALL_NO_KW_METHOD_DESCRIPTOR_O , CALL_NO_KW_STR_1 , CALL_NO_KW_TUPLE_1 ,
3170
3184
CALL_NO_KW_TYPE_1 };
3171
- family (for_iter , INLINE_CACHE_ENTRIES_FOR_ITER ) = {
3172
- FOR_ITER , FOR_ITER_LIST ,
3173
- FOR_ITER_RANGE };
3174
3185
family (store_fast ) = { STORE_FAST , STORE_FAST__LOAD_FAST , STORE_FAST__STORE_FAST };
3175
3186
family (unpack_sequence , INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE ) = {
3176
3187
UNPACK_SEQUENCE , UNPACK_SEQUENCE_LIST ,
0 commit comments