Skip to content

Commit eedbe8b

Browse files
committed
Fix FOR_ITER for tier 2
1 parent ec12559 commit eedbe8b

File tree

10 files changed

+122
-173
lines changed

10 files changed

+122
-173
lines changed

Include/internal/pycore_ceval.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,8 @@ PyAPI_FUNC(_PyStackRef) _PyFloat_FromDouble_ConsumeInputs(_PyStackRef left, _PyS
353353
extern int _PyRunRemoteDebugger(PyThreadState *tstate);
354354
#endif
355355

356-
_PyStackRef _PyForIter_NextWithIndex(PyObject *seq, _PyStackRef index);
356+
_PyStackRef
357+
_PyForIter_VirtualIteratorNext(PyThreadState* tstate, struct _PyInterpreterFrame* frame, _PyStackRef iter, _PyStackRef *index_ptr);
357358

358359
#ifdef __cplusplus
359360
}

Include/internal/pycore_stackref.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,15 @@ PyAPI_FUNC(void) _Py_stackref_record_borrow(_PyStackRef ref, const char *filenam
6262
extern void _Py_stackref_associate(PyInterpreterState *interp, PyObject *obj, _PyStackRef ref);
6363

6464
static const _PyStackRef PyStackRef_NULL = { .index = 0 };
65+
static const _PyStackRef PyStackRef_ERROR = { .index = 2 };
6566

6667
// Use the first 3 even numbers for None, True and False.
6768
// Odd numbers are reserved for (tagged) integers
68-
#define PyStackRef_None ((_PyStackRef){ .index = 2 } )
69-
#define PyStackRef_False ((_PyStackRef){ .index = 4 })
70-
#define PyStackRef_True ((_PyStackRef){ .index = 6 })
69+
#define PyStackRef_None ((_PyStackRef){ .index = 4 } )
70+
#define PyStackRef_False ((_PyStackRef){ .index = 6 })
71+
#define PyStackRef_True ((_PyStackRef){ .index = 8 })
7172

72-
#define INITIAL_STACKREF_INDEX 8
73+
#define INITIAL_STACKREF_INDEX 10
7374

7475
static inline int
7576
PyStackRef_IsNull(_PyStackRef ref)
@@ -241,9 +242,23 @@ PyStackRef_IsNullOrInt(_PyStackRef ref);
241242
#else
242243

243244
#define Py_INT_TAG 3
245+
#define Py_TAG_INVALID 2
244246
#define Py_TAG_REFCNT 1
245247
#define Py_TAG_BITS 3
246248

249+
static inline bool
250+
PyStackRef_IsError(_PyStackRef ref)
251+
{
252+
return ref.bits == Py_TAG_INVALID;
253+
}
254+
255+
static inline bool
256+
PyStackRef_IsValid(_PyStackRef ref)
257+
{
258+
/* Invalid values are ERROR and NULL */
259+
return ref.bits >= Py_INT_TAG;
260+
}
261+
247262
static inline bool
248263
PyStackRef_IsTaggedInt(_PyStackRef i)
249264
{
@@ -284,6 +299,8 @@ PyStackRef_IncrementTaggedIntNoOverflow(_PyStackRef ref)
284299

285300

286301
static const _PyStackRef PyStackRef_NULL = { .bits = Py_TAG_DEFERRED};
302+
static const _PyStackRef PyStackRef_ERROR = { .bits = Py_TAG_INVALID};
303+
287304
#define PyStackRef_IsNull(stackref) ((stackref).bits == PyStackRef_NULL.bits)
288305
#define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) | Py_TAG_DEFERRED })
289306
#define PyStackRef_False ((_PyStackRef){.bits = ((uintptr_t)&_Py_FalseStruct) | Py_TAG_DEFERRED })
@@ -464,6 +481,7 @@ PyStackRef_AsStrongReference(_PyStackRef stackref)
464481

465482
#define PyStackRef_NULL_BITS Py_TAG_REFCNT
466483
static const _PyStackRef PyStackRef_NULL = { .bits = PyStackRef_NULL_BITS };
484+
static const _PyStackRef PyStackRef_ERROR = { .bits = Py_TAG_INVALID };
467485

468486
#define PyStackRef_IsNull(ref) ((ref).bits == PyStackRef_NULL_BITS)
469487
#define PyStackRef_True ((_PyStackRef){.bits = ((uintptr_t)&_Py_TrueStruct) | Py_TAG_REFCNT })

Python/bytecodes.c

Lines changed: 21 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -3125,100 +3125,47 @@ dummy_func(
31253125
}
31263126

31273127
replaced op(_FOR_ITER, (iter, null_or_index -- iter, null_or_index, next)) {
3128-
/* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */
3129-
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
3130-
if (PyStackRef_IsTaggedInt(null_or_index)) {
3131-
next = _PyForIter_NextWithIndex(iter_o, null_or_index);
3132-
if (PyStackRef_IsNull(next)) {
3133-
JUMPBY(oparg + 1);
3134-
DISPATCH();
3135-
}
3136-
null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index);
3137-
}
3138-
else {
3139-
PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
3140-
if (next_o == NULL) {
3141-
if (_PyErr_Occurred(tstate)) {
3142-
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
3143-
if (!matches) {
3144-
ERROR_NO_POP();
3145-
}
3146-
_PyEval_MonitorRaise(tstate, frame, this_instr);
3147-
_PyErr_Clear(tstate);
3148-
}
3149-
/* iterator ended normally */
3150-
assert(next_instr[oparg].op.code == END_FOR ||
3151-
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
3152-
/* Jump forward oparg, then skip following END_FOR */
3153-
JUMPBY(oparg + 1);
3154-
DISPATCH();
3128+
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, &null_or_index);
3129+
if (!PyStackRef_IsValid(item)) {
3130+
if (PyStackRef_IsError(item)) {
3131+
ERROR_NO_POP();
31553132
}
3156-
next = PyStackRef_FromPyObjectSteal(next_o);
3133+
JUMPBY(oparg + 1);
3134+
DISPATCH();
31573135
}
3136+
next = item;
31583137
}
31593138

31603139
op(_FOR_ITER_TIER_TWO, (iter, null_or_index -- iter, null_or_index, next)) {
3161-
/* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */
3162-
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
3163-
EXIT_IF(!PyStackRef_IsNull(null_or_index));
3164-
PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
3165-
if (next_o == NULL) {
3166-
if (_PyErr_Occurred(tstate)) {
3167-
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
3168-
if (!matches) {
3169-
ERROR_NO_POP();
3170-
}
3171-
_PyEval_MonitorRaise(tstate, frame, frame->instr_ptr);
3172-
_PyErr_Clear(tstate);
3140+
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, &null_or_index);
3141+
if (!PyStackRef_IsValid(item)) {
3142+
if (PyStackRef_IsError(item)) {
3143+
ERROR_NO_POP();
31733144
}
31743145
/* iterator ended normally */
31753146
/* The translator sets the deopt target just past the matching END_FOR */
31763147
EXIT_IF(true);
31773148
}
3178-
next = PyStackRef_FromPyObjectSteal(next_o);
3179-
// Common case: no jump, leave it to the code generator
3149+
next = item;
31803150
}
31813151

3152+
31823153
macro(FOR_ITER) = _SPECIALIZE_FOR_ITER + _FOR_ITER;
31833154

31843155

31853156
inst(INSTRUMENTED_FOR_ITER, (unused/1, iter, null_or_index -- iter, null_or_index, next)) {
3186-
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
3187-
if (PyStackRef_IsTaggedInt(null_or_index)) {
3188-
next = _PyForIter_NextWithIndex(iter_o, null_or_index);
3189-
if (PyStackRef_IsNull(next)) {
3190-
JUMPBY(oparg + 1);
3191-
DISPATCH();
3192-
}
3193-
null_or_index = PyStackRef_IncrementTaggedIntNoOverflow(null_or_index);
3194-
INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT);
3195-
}
3196-
else {
3197-
PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
3198-
if (next_o != NULL) {
3199-
next = PyStackRef_FromPyObjectSteal(next_o);
3200-
INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT);
3201-
}
3202-
else {
3203-
if (_PyErr_Occurred(tstate)) {
3204-
int matches = _PyErr_ExceptionMatches(tstate, PyExc_StopIteration);
3205-
if (!matches) {
3206-
ERROR_NO_POP();
3207-
}
3208-
_PyEval_MonitorRaise(tstate, frame, this_instr);
3209-
_PyErr_Clear(tstate);
3210-
}
3211-
/* iterator ended normally */
3212-
assert(next_instr[oparg].op.code == END_FOR ||
3213-
next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
3214-
/* Skip END_FOR */
3215-
JUMPBY(oparg + 1);
3216-
DISPATCH();
3157+
_PyStackRef item = _PyForIter_VirtualIteratorNext(tstate, frame, iter, &null_or_index);
3158+
if (!PyStackRef_IsValid(item)) {
3159+
if (PyStackRef_IsError(item)) {
3160+
ERROR_NO_POP();
32173161
}
3162+
JUMPBY(oparg + 1);
3163+
DISPATCH();
32183164
}
3165+
next = item;
3166+
INSTRUMENTED_JUMP(this_instr, next_instr, PY_MONITORING_EVENT_BRANCH_LEFT);
32193167
}
32203168

3221-
32223169
op(_ITER_CHECK_LIST, (iter, null_or_index -- iter, null_or_index)) {
32233170
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
32243171
EXIT_IF(Py_TYPE(iter_o) != &PyList_Type);

Python/ceval.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3439,8 +3439,8 @@ _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *na
34393439
return value;
34403440
}
34413441

3442-
_PyStackRef
3443-
_PyForIter_NextWithIndex(PyObject *seq, _PyStackRef index)
3442+
static _PyStackRef
3443+
foriter_next(PyObject *seq, _PyStackRef index)
34443444
{
34453445
assert(PyStackRef_IsTaggedInt(index));
34463446
assert(PyTuple_CheckExact(seq) || PyList_CheckExact(seq));
@@ -3459,6 +3459,30 @@ _PyForIter_NextWithIndex(PyObject *seq, _PyStackRef index)
34593459
return PyStackRef_FromPyObjectSteal(item);
34603460
}
34613461

3462+
_PyStackRef _PyForIter_VirtualIteratorNext(PyThreadState* tstate, _PyInterpreterFrame* frame, _PyStackRef iter, _PyStackRef* index_ptr)
3463+
{
3464+
PyObject *iter_o = PyStackRef_AsPyObjectBorrow(iter);
3465+
_PyStackRef index = *index_ptr;
3466+
if (PyStackRef_IsTaggedInt(index)) {
3467+
*index_ptr = PyStackRef_IncrementTaggedIntNoOverflow(index);
3468+
return foriter_next(iter_o, index);
3469+
}
3470+
PyObject *next_o = (*Py_TYPE(iter_o)->tp_iternext)(iter_o);
3471+
if (next_o == NULL) {
3472+
if (_PyErr_Occurred(tstate)) {
3473+
if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
3474+
_PyEval_MonitorRaise(tstate, frame, frame->instr_ptr);
3475+
_PyErr_Clear(tstate);
3476+
}
3477+
else {
3478+
return PyStackRef_ERROR;
3479+
}
3480+
}
3481+
return PyStackRef_NULL;
3482+
}
3483+
return PyStackRef_FromPyObjectSteal(next_o);
3484+
}
3485+
34623486
/* Check if a 'cls' provides the given special method. */
34633487
static inline int
34643488
type_has_special_method(PyTypeObject *cls, PyObject *name)

Python/executor_cases.c.h

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

Python/generated_cases.c.h

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

0 commit comments

Comments
 (0)