Skip to content

Commit 46cc9f9

Browse files
committed
Virtual iterators. Work in progress
1 parent 31eb2d3 commit 46cc9f9

File tree

11 files changed

+120
-63
lines changed

11 files changed

+120
-63
lines changed

Include/internal/pycore_magic_number.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ Known values:
274274
Python 3.14a6 3619 (Renumber RESUME opcode from 149 to 128)
275275
Python 3.14a6 3620 (Optimize bytecode for all/any/tuple called on a genexp)
276276
Python 3.14a7 3621 (Optimize LOAD_FAST opcodes into LOAD_FAST_BORROW)
277+
Python 3.14a8 3622 (Virtual iterators)
277278
278279
Python 3.15 will start with 3650
279280
@@ -286,7 +287,7 @@ PC/launcher.c must also be updated.
286287
287288
*/
288289

289-
#define PYC_MAGIC_NUMBER 3621
290+
#define PYC_MAGIC_NUMBER 3622
290291
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
291292
(little-endian) and then appending b'\r\n'. */
292293
#define PYC_MAGIC_NUMBER_TOKEN \

Include/internal/pycore_opcode_metadata.h

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_ids.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/bytecodes.c

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,12 @@ dummy_func(
405405
PyStackRef_CLOSE(value);
406406
}
407407

408-
macro(POP_ITER) = POP_TOP;
408+
409+
inst(POP_ITER, (iter, index_or_null -- )) {
410+
(void)index_or_null;
411+
DEAD(index_or_null);
412+
PyStackRef_CLOSE(iter);
413+
}
409414

410415
no_save_ip tier1 inst(INSTRUMENTED_END_FOR, (receiver, value -- receiver)) {
411416
/* Need to create a fake StopIteration error here,
@@ -419,7 +424,9 @@ dummy_func(
419424
PyStackRef_CLOSE(value);
420425
}
421426

422-
tier1 inst(INSTRUMENTED_POP_ITER, (iter -- )) {
427+
tier1 inst(INSTRUMENTED_POP_ITER, (iter, index_or_null -- )) {
428+
(void)index_or_null;
429+
DEAD(index_or_null);
423430
INSTRUMENTED_JUMP(prev_instr, this_instr+1, PY_MONITORING_EVENT_BRANCH_RIGHT);
424431
PyStackRef_CLOSE(iter);
425432
}
@@ -2972,12 +2979,13 @@ dummy_func(
29722979
values_or_none = PyStackRef_FromPyObjectSteal(values_or_none_o);
29732980
}
29742981

2975-
inst(GET_ITER, (iterable -- iter)) {
2982+
inst(GET_ITER, (iterable -- iter, null)) {
29762983
/* before: [obj]; after [getiter(obj)] */
29772984
PyObject *iter_o = PyObject_GetIter(PyStackRef_AsPyObjectBorrow(iterable));
29782985
PyStackRef_CLOSE(iterable);
29792986
ERROR_IF(iter_o == NULL, error);
29802987
iter = PyStackRef_FromPyObjectSteal(iter_o);
2988+
null = PyStackRef_NULL;
29812989
}
29822990

29832991
inst(GET_YIELD_FROM_ITER, (iterable -- iter)) {
@@ -3024,7 +3032,7 @@ dummy_func(
30243032
FOR_ITER_GEN,
30253033
};
30263034

3027-
specializing op(_SPECIALIZE_FOR_ITER, (counter/1, iter -- iter)) {
3035+
specializing op(_SPECIALIZE_FOR_ITER, (counter/1, iter, null_or_index -- iter, null_or_index)) {
30283036
#if ENABLE_SPECIALIZATION_FT
30293037
if (ADAPTIVE_COUNTER_TRIGGERS(counter)) {
30303038
next_instr = this_instr;
@@ -3036,7 +3044,7 @@ dummy_func(
30363044
#endif /* ENABLE_SPECIALIZATION_FT */
30373045
}
30383046

3039-
replaced op(_FOR_ITER, (iter -- iter, next)) {
3047+
replaced op(_FOR_ITER, (iter, null_or_index -- iter, null_or_index, next)) {
30403048
/* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */
30413049
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
30423050
PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
@@ -3060,7 +3068,7 @@ dummy_func(
30603068
// Common case: no jump, leave it to the code generator
30613069
}
30623070

3063-
op(_FOR_ITER_TIER_TWO, (iter -- iter, next)) {
3071+
op(_FOR_ITER_TIER_TWO, (iter, null_or_index -- iter, null_or_index, next)) {
30643072
/* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */
30653073
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
30663074
PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
@@ -3084,7 +3092,7 @@ dummy_func(
30843092
macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER;
30853093

30863094

3087-
inst(INSTRUMENTED_FOR_ITER, (unused/1, iter -- iter, next)) {
3095+
inst(INSTRUMENTED_FOR_ITER, (unused/1, iter, null_or_index -- iter, null_or_index, next)) {
30883096
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
30893097
PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
30903098
if (next_o != NULL) {
@@ -3110,7 +3118,7 @@ dummy_func(
31103118
}
31113119

31123120

3113-
op(_ITER_CHECK_LIST, (iter -- iter)) {
3121+
op(_ITER_CHECK_LIST, (iter, null_or_index -- iter, null_or_index)) {
31143122
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
31153123
EXIT_IF(Py_TYPE(iter_o) != &PyListIter_Type);
31163124
#ifdef Py_GIL_DISABLED
@@ -3121,7 +3129,7 @@ dummy_func(
31213129
#endif
31223130
}
31233131

3124-
replaced op(_ITER_JUMP_LIST, (iter -- iter)) {
3132+
replaced op(_ITER_JUMP_LIST, (iter, null_or_index -- iter, null_or_index)) {
31253133
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
31263134
assert(Py_TYPE(iter_o) == &PyListIter_Type);
31273135
// For free-threaded Python, the loop exit can happen at any point during
@@ -3149,7 +3157,7 @@ dummy_func(
31493157
}
31503158

31513159
// Only used by Tier 2
3152-
op(_GUARD_NOT_EXHAUSTED_LIST, (iter -- iter)) {
3160+
op(_GUARD_NOT_EXHAUSTED_LIST, (iter, null_or_index -- iter, null_or_index)) {
31533161
#ifndef Py_GIL_DISABLED
31543162
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
31553163
_PyListIterObject *it = (_PyListIterObject *)iter_o;
@@ -3163,7 +3171,7 @@ dummy_func(
31633171
#endif
31643172
}
31653173

3166-
replaced op(_ITER_NEXT_LIST, (iter -- iter, next)) {
3174+
replaced op(_ITER_NEXT_LIST, (iter, null_or_index -- iter, null_or_index, next)) {
31673175
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
31683176
_PyListIterObject *it = (_PyListIterObject *)iter_o;
31693177
assert(Py_TYPE(iter_o) == &PyListIter_Type);
@@ -3192,7 +3200,7 @@ dummy_func(
31923200
}
31933201

31943202
// Only used by Tier 2
3195-
op(_ITER_NEXT_LIST_TIER_TWO, (iter -- iter, next)) {
3203+
op(_ITER_NEXT_LIST_TIER_TWO, (iter, null_or_index -- iter, null_or_index, next)) {
31963204
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
31973205
_PyListIterObject *it = (_PyListIterObject *)iter_o;
31983206
assert(Py_TYPE(iter_o) == &PyListIter_Type);
@@ -3224,15 +3232,15 @@ dummy_func(
32243232
_ITER_JUMP_LIST +
32253233
_ITER_NEXT_LIST;
32263234

3227-
op(_ITER_CHECK_TUPLE, (iter -- iter)) {
3235+
op(_ITER_CHECK_TUPLE, (iter, null_or_index -- iter, null_or_index)) {
32283236
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
32293237
EXIT_IF(Py_TYPE(iter_o) != &PyTupleIter_Type);
32303238
#ifdef Py_GIL_DISABLED
32313239
EXIT_IF(!_PyObject_IsUniquelyReferenced(iter_o));
32323240
#endif
32333241
}
32343242

3235-
replaced op(_ITER_JUMP_TUPLE, (iter -- iter)) {
3243+
replaced op(_ITER_JUMP_TUPLE, (iter, null_or_index -- iter, null_or_index)) {
32363244
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
32373245
(void)iter_o;
32383246
assert(Py_TYPE(iter_o) == &PyTupleIter_Type);
@@ -3256,7 +3264,7 @@ dummy_func(
32563264
}
32573265

32583266
// Only used by Tier 2
3259-
op(_GUARD_NOT_EXHAUSTED_TUPLE, (iter -- iter)) {
3267+
op(_GUARD_NOT_EXHAUSTED_TUPLE, (iter, null_or_index -- iter, null_or_index)) {
32603268
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
32613269
_PyTupleIterObject *it = (_PyTupleIterObject *)iter_o;
32623270
assert(Py_TYPE(iter_o) == &PyTupleIter_Type);
@@ -3268,7 +3276,7 @@ dummy_func(
32683276
EXIT_IF(it->it_index >= PyTuple_GET_SIZE(seq));
32693277
}
32703278

3271-
op(_ITER_NEXT_TUPLE, (iter -- iter, next)) {
3279+
op(_ITER_NEXT_TUPLE, (iter, null_or_index -- iter, null_or_index, next)) {
32723280
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
32733281
_PyTupleIterObject *it = (_PyTupleIterObject *)iter_o;
32743282
assert(Py_TYPE(iter_o) == &PyTupleIter_Type);
@@ -3295,7 +3303,7 @@ dummy_func(
32953303
#endif
32963304
}
32973305

3298-
replaced op(_ITER_JUMP_RANGE, (iter -- iter)) {
3306+
replaced op(_ITER_JUMP_RANGE, (iter, null_or_index -- iter, null_or_index)) {
32993307
_PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter);
33003308
assert(Py_TYPE(r) == &PyRangeIter_Type);
33013309
#ifdef Py_GIL_DISABLED
@@ -3310,13 +3318,13 @@ dummy_func(
33103318
}
33113319

33123320
// Only used by Tier 2
3313-
op(_GUARD_NOT_EXHAUSTED_RANGE, (iter -- iter)) {
3321+
op(_GUARD_NOT_EXHAUSTED_RANGE, (iter, null_or_index -- iter, null_or_index)) {
33143322
_PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter);
33153323
assert(Py_TYPE(r) == &PyRangeIter_Type);
33163324
EXIT_IF(r->len <= 0);
33173325
}
33183326

3319-
op(_ITER_NEXT_RANGE, (iter -- iter, next)) {
3327+
op(_ITER_NEXT_RANGE, (iter, null_or_index -- iter, null_or_index, next)) {
33203328
_PyRangeIterObject *r = (_PyRangeIterObject *)PyStackRef_AsPyObjectBorrow(iter);
33213329
assert(Py_TYPE(r) == &PyRangeIter_Type);
33223330
#ifdef Py_GIL_DISABLED
@@ -3337,7 +3345,7 @@ dummy_func(
33373345
_ITER_JUMP_RANGE +
33383346
_ITER_NEXT_RANGE;
33393347

3340-
op(_FOR_ITER_GEN_FRAME, (iter -- iter, gen_frame: _PyInterpreterFrame*)) {
3348+
op(_FOR_ITER_GEN_FRAME, (iter, null -- iter, null, gen_frame: _PyInterpreterFrame*)) {
33413349
PyGenObject *gen = (PyGenObject *)PyStackRef_AsPyObjectBorrow(iter);
33423350
DEOPT_IF(Py_TYPE(gen) != &PyGen_Type);
33433351
#ifdef Py_GIL_DISABLED

Python/ceval.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ maybe_lltrace_resume_frame(_PyInterpreterFrame *frame, PyObject *globals)
267267
lltrace = *python_lltrace - '0'; // TODO: Parse an int and all that
268268
}
269269
}
270+
lltrace = 5;
270271
if (lltrace >= 5) {
271272
lltrace_resume_frame(frame);
272273
}

Python/codegen.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -527,9 +527,10 @@ codegen_unwind_fblock(compiler *c, location *ploc,
527527
case COMPILE_FBLOCK_FOR_LOOP:
528528
/* Pop the iterator */
529529
if (preserve_tos) {
530-
ADDOP_I(c, *ploc, SWAP, 2);
530+
ADDOP_I(c, *ploc, SWAP, 3);
531531
}
532532
ADDOP(c, *ploc, POP_TOP);
533+
ADDOP(c, *ploc, POP_TOP);
533534
return SUCCESS;
534535

535536
case COMPILE_FBLOCK_TRY_EXCEPT:

0 commit comments

Comments
 (0)