diff options
author | Thomas Wouters <thomas@python.org> | 2023-02-07 22:13:53 (GMT) |
---|---|---|
committer | Thomas Wouters <thomas@python.org> | 2023-02-07 22:13:53 (GMT) |
commit | 0d3d5007b136ff1bc0faa960d6526e047dd92396 (patch) | |
tree | 6f8bdeea32063127e8c63728244798dac1d3f06f | |
parent | 46f461be56ab90891d2d43240d80a0e19d100ba9 (diff) | |
parent | acc2f3b19d28d4bf3f8fb32357f581cba5ba24c7 (diff) | |
download | cpython-0d3d5007b136ff1bc0faa960d6526e047dd92396.zip cpython-0d3d5007b136ff1bc0faa960d6526e047dd92396.tar.gz cpython-0d3d5007b136ff1bc0faa960d6526e047dd92396.tar.bz2 |
Merge branch 'main' of https://github.com/python/cpython into main
-rw-r--r-- | Doc/library/asyncio-task.rst | 2 | ||||
-rw-r--r-- | Doc/requirements.txt | 2 | ||||
-rw-r--r-- | Doc/whatsnew/3.12.rst | 2 | ||||
-rw-r--r-- | Lib/test/test_fileio.py | 13 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst | 2 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 6 | ||||
-rw-r--r-- | Python/bytecodes.c | 120 | ||||
-rw-r--r-- | Python/generated_cases.c.h | 107 | ||||
-rw-r--r-- | Python/opcode_metadata.h | 46 |
9 files changed, 158 insertions, 142 deletions
diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst index 3911258..9b98424 100644 --- a/Doc/library/asyncio-task.rst +++ b/Doc/library/asyncio-task.rst @@ -1097,7 +1097,7 @@ Task Object The *limit* argument is passed to :meth:`get_stack` directly. The *file* argument is an I/O stream to which the output - is written; by default output is written to :data:`sys.stderr`. + is written; by default output is written to :data:`sys.stdout`. .. method:: get_coro() diff --git a/Doc/requirements.txt b/Doc/requirements.txt index 134f39d..71d3cd6 100644 --- a/Doc/requirements.txt +++ b/Doc/requirements.txt @@ -8,7 +8,7 @@ sphinx==4.5.0 blurb sphinx-lint==0.6.7 -sphinxext-opengraph>=0.7.1 +sphinxext-opengraph==0.7.5 # The theme used by the documentation is stored separately, so we need # to install that as well. diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst index 0c5a70b..b723b70 100644 --- a/Doc/whatsnew/3.12.rst +++ b/Doc/whatsnew/3.12.rst @@ -479,7 +479,7 @@ APIs: * :class:`webbrowser.MacOSX` (:gh:`86421`) Pending Removal in Python 3.14 -============================== +------------------------------ * Deprecated the following :mod:`importlib.abc` classes, scheduled for removal in Python 3.14: diff --git a/Lib/test/test_fileio.py b/Lib/test/test_fileio.py index 2263604..ebfcffd 100644 --- a/Lib/test/test_fileio.py +++ b/Lib/test/test_fileio.py @@ -12,7 +12,9 @@ from functools import wraps from test.support import ( cpython_only, swap_attr, gc_collect, is_emscripten, is_wasi ) -from test.support.os_helper import (TESTFN, TESTFN_UNICODE, make_bad_fd) +from test.support.os_helper import ( + TESTFN, TESTFN_ASCII, TESTFN_UNICODE, make_bad_fd, + ) from test.support.warnings_helper import check_warnings from collections import UserList @@ -431,18 +433,15 @@ class OtherFileTests: def testBytesOpen(self): # Opening a bytes filename - try: - fn = TESTFN.encode("ascii") - except UnicodeEncodeError: - self.skipTest('could not encode %r to ascii' % TESTFN) + fn = TESTFN_ASCII.encode("ascii") f = self.FileIO(fn, "w") try: f.write(b"abc") f.close() - with open(TESTFN, "rb") as f: + with open(TESTFN_ASCII, "rb") as f: self.assertEqual(f.read(), b"abc") finally: - os.unlink(TESTFN) + os.unlink(TESTFN_ASCII) @unittest.skipIf(sys.getfilesystemencoding() != 'utf-8', "test only works for utf-8 filesystems") diff --git a/Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst b/Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst new file mode 100644 index 0000000..fd9ea04 --- /dev/null +++ b/Misc/NEWS.d/next/Documentation/2023-02-07-21-43-24.gh-issue-97725.cuY7Cd.rst @@ -0,0 +1,2 @@ +Fix :meth:`asyncio.Task.print_stack` description for ``file=None``. +Patch by Oleg Iarygin. diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 5a6097e..8b2ce1a 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -3185,11 +3185,11 @@ eval_eval_code_ex(PyObject *mod, PyObject *pos_args) globals, locals, c_args, - c_args_len, + (int)c_args_len, c_kwargs, - c_kwargs_len, + (int)c_kwargs_len, c_defaults, - c_defaults_len, + (int)c_defaults_len, kw_defaults, closure ); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 0fc0b3b..b43625f 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -859,13 +859,11 @@ dummy_func( } } - // stack effect: (__0 -- __array[oparg]) - inst(UNPACK_SEQUENCE) { + inst(UNPACK_SEQUENCE, (unused/1, seq -- unused[oparg])) { #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *seq = TOP(); next_instr--; _Py_Specialize_UnpackSequence(seq, next_instr, oparg); DISPATCH_SAME_OPARG(); @@ -873,27 +871,19 @@ dummy_func( STAT_INC(UNPACK_SEQUENCE, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *seq = POP(); - PyObject **top = stack_pointer + oparg; - if (!unpack_iterable(tstate, seq, oparg, -1, top)) { - Py_DECREF(seq); - goto error; - } - STACK_GROW(oparg); + PyObject **top = stack_pointer + oparg - 1; + int res = unpack_iterable(tstate, seq, oparg, -1, top); Py_DECREF(seq); - JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); + ERROR_IF(res == 0, error); } - // stack effect: (__0 -- __array[oparg]) - inst(UNPACK_SEQUENCE_TWO_TUPLE) { - PyObject *seq = TOP(); + inst(UNPACK_SEQUENCE_TWO_TUPLE, (unused/1, seq -- v1, v0)) { DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); - SET_TOP(Py_NewRef(PyTuple_GET_ITEM(seq, 1))); - PUSH(Py_NewRef(PyTuple_GET_ITEM(seq, 0))); + v1 = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); + v0 = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); Py_DECREF(seq); - JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); } // stack effect: (__0 -- __array[oparg]) @@ -926,17 +916,12 @@ dummy_func( JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); } - // error: UNPACK_EX has irregular stack effect - inst(UNPACK_EX) { + inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >> 8])) { int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); - PyObject *seq = POP(); - PyObject **top = stack_pointer + totalargs; - if (!unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top)) { - Py_DECREF(seq); - goto error; - } - STACK_GROW(totalargs); + PyObject **top = stack_pointer + totalargs - 1; + int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); Py_DECREF(seq); + ERROR_IF(res == 0, error); } family(store_attr, INLINE_CACHE_ENTRIES_STORE_ATTR) = { @@ -2066,27 +2051,35 @@ dummy_func( PREDICT(LOAD_CONST); } - // stack effect: ( -- __0) - inst(FOR_ITER) { + // Most members of this family are "secretly" super-instructions. + // When the loop is exhausted, they jump, and the jump target is + // always END_FOR, which pops two values off the stack. + // This is optimized by skipping that instruction and combining + // its effect (popping 'iter' instead of pushing 'next'.) + + family(for_iter, INLINE_CACHE_ENTRIES_FOR_ITER) = { + FOR_ITER, + FOR_ITER_LIST, + FOR_ITER_TUPLE, + FOR_ITER_RANGE, + FOR_ITER_GEN, + }; + + inst(FOR_ITER, (unused/1, iter -- iter, next)) { #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_ForIter(TOP(), next_instr, oparg); + _Py_Specialize_ForIter(iter, next_instr, oparg); DISPATCH_SAME_OPARG(); } STAT_INC(FOR_ITER, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - /* before: [iter]; after: [iter, iter()] *or* [] */ - PyObject *iter = TOP(); - PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); - if (next != NULL) { - PUSH(next); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); - } - else { + /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ + next = (*Py_TYPE(iter)->tp_iternext)(iter); + if (next == NULL) { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { goto error; @@ -2098,63 +2091,66 @@ dummy_func( } /* iterator ended normally */ assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); - STACK_SHRINK(1); Py_DECREF(iter); - /* Skip END_FOR */ + STACK_SHRINK(1); + /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + DISPATCH(); } + // Common case: no jump, leave it to the code generator } - // stack effect: ( -- __0) - inst(FOR_ITER_LIST) { + inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) { assert(cframe.use_tracing == 0); - _PyListIterObject *it = (_PyListIterObject *)TOP(); - DEOPT_IF(Py_TYPE(it) != &PyListIter_Type, FOR_ITER); + DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); + _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); PyListObject *seq = it->it_seq; if (seq) { if (it->it_index < PyList_GET_SIZE(seq)) { - PyObject *next = PyList_GET_ITEM(seq, it->it_index++); - PUSH(Py_NewRef(next)); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); goto end_for_iter_list; // End of this instruction } it->it_seq = NULL; Py_DECREF(seq); } + Py_DECREF(iter); STACK_SHRINK(1); - Py_DECREF(it); + /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + DISPATCH(); end_for_iter_list: + // Common case: no jump, leave it to the code generator } - // stack effect: ( -- __0) - inst(FOR_ITER_TUPLE) { + inst(FOR_ITER_TUPLE, (unused/1, iter -- iter, next)) { assert(cframe.use_tracing == 0); - _PyTupleIterObject *it = (_PyTupleIterObject *)TOP(); + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); PyTupleObject *seq = it->it_seq; if (seq) { if (it->it_index < PyTuple_GET_SIZE(seq)) { - PyObject *next = PyTuple_GET_ITEM(seq, it->it_index++); - PUSH(Py_NewRef(next)); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); goto end_for_iter_tuple; // End of this instruction } it->it_seq = NULL; Py_DECREF(seq); } + Py_DECREF(iter); STACK_SHRINK(1); - Py_DECREF(it); + /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + DISPATCH(); end_for_iter_tuple: + // Common case: no jump, leave it to the code generator } - // stack effect: ( -- __0) - inst(FOR_ITER_RANGE) { + // This is slightly different, when the loop isn't terminated we + // jump over the immediately following STORE_FAST instruction. + inst(FOR_ITER_RANGE, (unused/1, iter -- iter, unused)) { assert(cframe.use_tracing == 0); - _PyRangeIterObject *r = (_PyRangeIterObject *)TOP(); + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); _Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER]; @@ -2162,6 +2158,7 @@ dummy_func( if (r->len <= 0) { STACK_SHRINK(1); Py_DECREF(r); + // Jump over END_FOR instruction. JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); } else { @@ -2174,11 +2171,13 @@ dummy_func( // The STORE_FAST is already done. JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + 1); } + DISPATCH(); } - inst(FOR_ITER_GEN) { + // This is *not* a super-instruction, unique in the family. + inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) { assert(cframe.use_tracing == 0); - PyGenObject *gen = (PyGenObject *)TOP(); + PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); STAT_INC(FOR_ITER, hit); @@ -3168,9 +3167,6 @@ family(call, INLINE_CACHE_ENTRIES_CALL) = { CALL_NO_KW_LIST_APPEND, CALL_NO_KW_METHOD_DESCRIPTOR_FAST, CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, CALL_NO_KW_METHOD_DESCRIPTOR_O, CALL_NO_KW_STR_1, CALL_NO_KW_TUPLE_1, CALL_NO_KW_TYPE_1 }; -family(for_iter, INLINE_CACHE_ENTRIES_FOR_ITER) = { - FOR_ITER, FOR_ITER_LIST, - FOR_ITER_RANGE }; family(store_fast) = { STORE_FAST, STORE_FAST__LOAD_FAST, STORE_FAST__STORE_FAST }; family(unpack_sequence, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = { UNPACK_SEQUENCE, UNPACK_SEQUENCE_LIST, diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index f0f314a..ab19f43 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -1108,11 +1108,11 @@ TARGET(UNPACK_SEQUENCE) { PREDICTED(UNPACK_SEQUENCE); + PyObject *seq = PEEK(1); #if ENABLE_SPECIALIZATION _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); - PyObject *seq = TOP(); next_instr--; _Py_Specialize_UnpackSequence(seq, next_instr, oparg); DISPATCH_SAME_OPARG(); @@ -1120,27 +1120,30 @@ STAT_INC(UNPACK_SEQUENCE, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - PyObject *seq = POP(); - PyObject **top = stack_pointer + oparg; - if (!unpack_iterable(tstate, seq, oparg, -1, top)) { - Py_DECREF(seq); - goto error; - } - STACK_GROW(oparg); + PyObject **top = stack_pointer + oparg - 1; + int res = unpack_iterable(tstate, seq, oparg, -1, top); Py_DECREF(seq); - JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); + if (res == 0) goto pop_1_error; + STACK_SHRINK(1); + STACK_GROW(oparg); + JUMPBY(1); DISPATCH(); } TARGET(UNPACK_SEQUENCE_TWO_TUPLE) { - PyObject *seq = TOP(); + PyObject *seq = PEEK(1); + PyObject *v1; + PyObject *v0; DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE); DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE); STAT_INC(UNPACK_SEQUENCE, hit); - SET_TOP(Py_NewRef(PyTuple_GET_ITEM(seq, 1))); - PUSH(Py_NewRef(PyTuple_GET_ITEM(seq, 0))); + v1 = Py_NewRef(PyTuple_GET_ITEM(seq, 1)); + v0 = Py_NewRef(PyTuple_GET_ITEM(seq, 0)); Py_DECREF(seq); - JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE); + STACK_GROW(1); + POKE(1, v0); + POKE(2, v1); + JUMPBY(1); DISPATCH(); } @@ -1175,15 +1178,13 @@ } TARGET(UNPACK_EX) { + PyObject *seq = PEEK(1); int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); - PyObject *seq = POP(); - PyObject **top = stack_pointer + totalargs; - if (!unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top)) { - Py_DECREF(seq); - goto error; - } - STACK_GROW(totalargs); + PyObject **top = stack_pointer + totalargs - 1; + int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top); Py_DECREF(seq); + if (res == 0) goto pop_1_error; + STACK_GROW((oparg & 0xFF) + (oparg >> 8)); DISPATCH(); } @@ -2619,25 +2620,23 @@ TARGET(FOR_ITER) { PREDICTED(FOR_ITER); + static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size"); + PyObject *iter = PEEK(1); + PyObject *next; #if ENABLE_SPECIALIZATION _PyForIterCache *cache = (_PyForIterCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { assert(cframe.use_tracing == 0); next_instr--; - _Py_Specialize_ForIter(TOP(), next_instr, oparg); + _Py_Specialize_ForIter(iter, next_instr, oparg); DISPATCH_SAME_OPARG(); } STAT_INC(FOR_ITER, deferred); DECREMENT_ADAPTIVE_COUNTER(cache->counter); #endif /* ENABLE_SPECIALIZATION */ - /* before: [iter]; after: [iter, iter()] *or* [] */ - PyObject *iter = TOP(); - PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); - if (next != NULL) { - PUSH(next); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); - } - else { + /* before: [iter]; after: [iter, iter()] *or* [] (and jump over END_FOR.) */ + next = (*Py_TYPE(iter)->tp_iternext)(iter); + if (next == NULL) { if (_PyErr_Occurred(tstate)) { if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { goto error; @@ -2649,63 +2648,81 @@ } /* iterator ended normally */ assert(_Py_OPCODE(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg]) == END_FOR); - STACK_SHRINK(1); Py_DECREF(iter); - /* Skip END_FOR */ + STACK_SHRINK(1); + /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + DISPATCH(); } + // Common case: no jump, leave it to the code generator + STACK_GROW(1); + POKE(1, next); + JUMPBY(1); DISPATCH(); } TARGET(FOR_ITER_LIST) { + PyObject *iter = PEEK(1); + PyObject *next; assert(cframe.use_tracing == 0); - _PyListIterObject *it = (_PyListIterObject *)TOP(); - DEOPT_IF(Py_TYPE(it) != &PyListIter_Type, FOR_ITER); + DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER); + _PyListIterObject *it = (_PyListIterObject *)iter; STAT_INC(FOR_ITER, hit); PyListObject *seq = it->it_seq; if (seq) { if (it->it_index < PyList_GET_SIZE(seq)) { - PyObject *next = PyList_GET_ITEM(seq, it->it_index++); - PUSH(Py_NewRef(next)); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + next = Py_NewRef(PyList_GET_ITEM(seq, it->it_index++)); goto end_for_iter_list; // End of this instruction } it->it_seq = NULL; Py_DECREF(seq); } + Py_DECREF(iter); STACK_SHRINK(1); - Py_DECREF(it); + /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + DISPATCH(); end_for_iter_list: + // Common case: no jump, leave it to the code generator + STACK_GROW(1); + POKE(1, next); + JUMPBY(1); DISPATCH(); } TARGET(FOR_ITER_TUPLE) { + PyObject *iter = PEEK(1); + PyObject *next; assert(cframe.use_tracing == 0); - _PyTupleIterObject *it = (_PyTupleIterObject *)TOP(); + _PyTupleIterObject *it = (_PyTupleIterObject *)iter; DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); PyTupleObject *seq = it->it_seq; if (seq) { if (it->it_index < PyTuple_GET_SIZE(seq)) { - PyObject *next = PyTuple_GET_ITEM(seq, it->it_index++); - PUSH(Py_NewRef(next)); - JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER); + next = Py_NewRef(PyTuple_GET_ITEM(seq, it->it_index++)); goto end_for_iter_tuple; // End of this instruction } it->it_seq = NULL; Py_DECREF(seq); } + Py_DECREF(iter); STACK_SHRINK(1); - Py_DECREF(it); + /* Jump forward oparg, then skip following END_FOR instruction */ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); + DISPATCH(); end_for_iter_tuple: + // Common case: no jump, leave it to the code generator + STACK_GROW(1); + POKE(1, next); + JUMPBY(1); DISPATCH(); } TARGET(FOR_ITER_RANGE) { + PyObject *iter = PEEK(1); assert(cframe.use_tracing == 0); - _PyRangeIterObject *r = (_PyRangeIterObject *)TOP(); + _PyRangeIterObject *r = (_PyRangeIterObject *)iter; DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER); STAT_INC(FOR_ITER, hit); _Py_CODEUNIT next = next_instr[INLINE_CACHE_ENTRIES_FOR_ITER]; @@ -2713,6 +2730,7 @@ if (r->len <= 0) { STACK_SHRINK(1); Py_DECREF(r); + // Jump over END_FOR instruction. JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1); } else { @@ -2729,8 +2747,9 @@ } TARGET(FOR_ITER_GEN) { + PyObject *iter = PEEK(1); assert(cframe.use_tracing == 0); - PyGenObject *gen = (PyGenObject *)TOP(); + PyGenObject *gen = (PyGenObject *)iter; DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER); DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER); STAT_INC(FOR_ITER, hit); diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h index 948d175..d258535 100644 --- a/Python/opcode_metadata.h +++ b/Python/opcode_metadata.h @@ -121,15 +121,15 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { case DELETE_NAME: return 0; case UNPACK_SEQUENCE: - return -1; + return 1; case UNPACK_SEQUENCE_TWO_TUPLE: - return -1; + return 1; case UNPACK_SEQUENCE_TUPLE: return -1; case UNPACK_SEQUENCE_LIST: return -1; case UNPACK_EX: - return -1; + return 1; case STORE_ATTR: return 2; case DELETE_ATTR: @@ -261,15 +261,15 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) { case GET_YIELD_FROM_ITER: return 1; case FOR_ITER: - return -1; + return 1; case FOR_ITER_LIST: - return -1; + return 1; case FOR_ITER_TUPLE: - return -1; + return 1; case FOR_ITER_RANGE: - return -1; + return 1; case FOR_ITER_GEN: - return -1; + return 1; case BEFORE_ASYNC_WITH: return 1; case BEFORE_WITH: @@ -467,15 +467,15 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { case DELETE_NAME: return 0; case UNPACK_SEQUENCE: - return -1; + return oparg; case UNPACK_SEQUENCE_TWO_TUPLE: - return -1; + return 2; case UNPACK_SEQUENCE_TUPLE: return -1; case UNPACK_SEQUENCE_LIST: return -1; case UNPACK_EX: - return -1; + return (oparg & 0xFF) + (oparg >> 8) + 1; case STORE_ATTR: return 0; case DELETE_ATTR: @@ -607,15 +607,15 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) { case GET_YIELD_FROM_ITER: return 1; case FOR_ITER: - return -1; + return 2; case FOR_ITER_LIST: - return -1; + return 2; case FOR_ITER_TUPLE: - return -1; + return 2; case FOR_ITER_RANGE: - return -1; + return 2; case FOR_ITER_GEN: - return -1; + return 2; case BEFORE_ASYNC_WITH: return 2; case BEFORE_WITH: @@ -759,8 +759,8 @@ struct opcode_metadata { [LOAD_BUILD_CLASS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [STORE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [DELETE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNPACK_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [UNPACK_SEQUENCE_TWO_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, + [UNPACK_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [UNPACK_SEQUENCE_TWO_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC }, [UNPACK_SEQUENCE_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [UNPACK_SEQUENCE_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, [UNPACK_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, @@ -829,11 +829,11 @@ struct opcode_metadata { [MATCH_KEYS] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [GET_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [GET_YIELD_FROM_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, - [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, - [FOR_ITER_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB }, + [FOR_ITER] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [FOR_ITER_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [FOR_ITER_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [FOR_ITER_RANGE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, + [FOR_ITER_GEN] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC }, [BEFORE_ASYNC_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [BEFORE_WITH] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, [WITH_EXCEPT_START] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IX }, |