From f7c220a20cfb6392ceb71cde024b9e023cda77dc Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 20 Feb 2022 01:17:02 -0500 Subject: [PATCH 01/21] Implement FOR_END --- Include/opcode.h | 60 ++++++++++--------- Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 3 + Programs/test_frozenmain.h | 60 ++++++++++--------- Python/ceval.c | 89 +++++++++++++++++++++------- Python/compile.c | 9 +-- Python/opcode_targets.h | 26 ++++---- Python/specialize.c | 3 + 8 files changed, 153 insertions(+), 99 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index df93a93fbbd989..9913d7d311e13e 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -113,6 +113,7 @@ extern "C" { #define PRECALL 166 #define CALL 171 #define KW_NAMES 172 +#define FOR_END 173 #define BINARY_OP_ADAPTIVE 3 #define BINARY_OP_ADD_INT 4 #define BINARY_OP_ADD_FLOAT 5 @@ -151,33 +152,34 @@ extern "C" { #define CALL_NO_KW_TYPE_1 55 #define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 56 #define JUMP_ABSOLUTE_QUICK 57 -#define LOAD_ATTR_ADAPTIVE 58 -#define LOAD_ATTR_INSTANCE_VALUE 59 -#define LOAD_ATTR_WITH_HINT 62 -#define LOAD_ATTR_SLOT 63 -#define LOAD_ATTR_MODULE 64 -#define LOAD_GLOBAL_ADAPTIVE 65 -#define LOAD_GLOBAL_MODULE 66 -#define LOAD_GLOBAL_BUILTIN 67 -#define LOAD_METHOD_ADAPTIVE 72 -#define LOAD_METHOD_CACHED 76 -#define LOAD_METHOD_CLASS 77 -#define LOAD_METHOD_MODULE 78 -#define LOAD_METHOD_NO_DICT 79 -#define RESUME_QUICK 80 -#define STORE_ATTR_ADAPTIVE 81 -#define STORE_ATTR_INSTANCE_VALUE 131 -#define STORE_ATTR_SLOT 140 -#define STORE_ATTR_WITH_HINT 141 -#define UNPACK_SEQUENCE_ADAPTIVE 143 -#define UNPACK_SEQUENCE_LIST 150 -#define UNPACK_SEQUENCE_TUPLE 153 -#define UNPACK_SEQUENCE_TWO_TUPLE 154 -#define LOAD_FAST__LOAD_FAST 158 -#define STORE_FAST__LOAD_FAST 159 -#define LOAD_FAST__LOAD_CONST 161 -#define LOAD_CONST__LOAD_FAST 167 -#define STORE_FAST__STORE_FAST 168 +#define FOR_END_QUICK 58 +#define LOAD_ATTR_ADAPTIVE 59 +#define LOAD_ATTR_INSTANCE_VALUE 62 +#define LOAD_ATTR_WITH_HINT 63 +#define LOAD_ATTR_SLOT 64 +#define LOAD_ATTR_MODULE 65 +#define LOAD_GLOBAL_ADAPTIVE 66 +#define LOAD_GLOBAL_MODULE 67 +#define LOAD_GLOBAL_BUILTIN 72 +#define LOAD_METHOD_ADAPTIVE 76 +#define LOAD_METHOD_CACHED 77 +#define LOAD_METHOD_CLASS 78 +#define LOAD_METHOD_MODULE 79 +#define LOAD_METHOD_NO_DICT 80 +#define RESUME_QUICK 81 +#define STORE_ATTR_ADAPTIVE 131 +#define STORE_ATTR_INSTANCE_VALUE 140 +#define STORE_ATTR_SLOT 141 +#define STORE_ATTR_WITH_HINT 143 +#define UNPACK_SEQUENCE_ADAPTIVE 150 +#define UNPACK_SEQUENCE_LIST 153 +#define UNPACK_SEQUENCE_TUPLE 154 +#define UNPACK_SEQUENCE_TWO_TUPLE 158 +#define LOAD_FAST__LOAD_FAST 159 +#define STORE_FAST__LOAD_FAST 161 +#define LOAD_FAST__LOAD_CONST 167 +#define LOAD_CONST__LOAD_FAST 168 +#define STORE_FAST__STORE_FAST 169 #define DO_TRACING 255 #ifdef NEED_OPCODE_JUMP_TABLES static uint32_t _PyOpcode_RelativeJump[8] = { @@ -186,7 +188,7 @@ static uint32_t _PyOpcode_RelativeJump[8] = { 536870912U, 134234112U, 0U, - 0U, + 8192U, 0U, 0U, }; @@ -196,7 +198,7 @@ static uint32_t _PyOpcode_Jump[8] = { 536870912U, 2316288000U, 67U, - 0U, + 8192U, 0U, 0U, }; diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 85f50eb958e31d..f704f805786605 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -403,7 +403,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3479).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3485).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py index 95792459c377a1..ff84b78b25014a 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -194,6 +194,8 @@ def jabs_op(name, op): def_op('KW_NAMES', 172) hasconst.append(172) +jrel_op('FOR_END', 173) + del def_op, name_op, jrel_op, jabs_op _nb_ops = [ @@ -264,6 +266,7 @@ def jabs_op(name, op): "CALL_NO_KW_TYPE_1", "CALL_NO_KW_METHOD_DESCRIPTOR_FAST", "JUMP_ABSOLUTE_QUICK", + "FOR_END_QUICK", "LOAD_ATTR_ADAPTIVE", "LOAD_ATTR_INSTANCE_VALUE", "LOAD_ATTR_WITH_HINT", diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index a7f6b6022a49e0..848845739004bc 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,37 +1,39 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, - 0,0,0,0,0,115,104,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,115,114,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, 100,2,166,1,171,0,1,0,2,0,101,2,100,3,101,0, 106,3,166,2,171,0,1,0,2,0,101,1,106,4,166,0, - 171,0,100,4,25,0,90,5,100,5,68,0,93,16,90,6, + 171,0,100,4,25,0,90,5,100,5,68,0,93,21,90,6, 2,0,101,2,100,6,101,6,155,0,100,7,101,5,101,6, - 25,0,155,0,157,4,166,1,171,0,1,0,113,33,100,1, - 83,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122, - 101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8, - 115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103, - 41,5,90,12,112,114,111,103,114,97,109,95,110,97,109,101, - 218,10,101,120,101,99,117,116,97,98,108,101,90,15,117,115, - 101,95,101,110,118,105,114,111,110,109,101,110,116,90,17,99, - 111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,111, - 90,14,98,117,102,102,101,114,101,100,95,115,116,100,105,111, - 122,7,99,111,110,102,105,103,32,122,2,58,32,41,7,218, - 3,115,121,115,90,17,95,116,101,115,116,105,110,116,101,114, - 110,97,108,99,97,112,105,218,5,112,114,105,110,116,218,4, - 97,114,103,118,90,11,103,101,116,95,99,111,110,102,105,103, - 115,114,2,0,0,0,218,3,107,101,121,169,0,243,0,0, - 0,0,250,18,116,101,115,116,95,102,114,111,122,101,110,109, - 97,105,110,46,112,121,250,8,60,109,111,100,117,108,101,62, - 114,11,0,0,0,1,0,0,0,115,18,0,0,0,2,128, - 8,3,8,1,12,2,16,1,16,1,8,1,30,7,4,249, - 115,20,0,0,0,2,128,8,3,8,1,12,2,16,1,16, - 1,2,7,4,1,2,249,34,7,115,104,0,0,0,0,0, - 1,11,1,11,1,11,1,11,1,25,1,25,1,25,1,25, - 1,6,1,6,7,27,1,28,1,28,1,28,1,6,1,6, - 7,17,19,22,19,27,1,28,1,28,1,28,10,39,10,27, - 10,39,10,41,10,41,42,50,10,51,1,7,12,2,1,42, - 1,42,5,8,5,10,5,10,11,41,21,24,11,41,11,41, - 28,34,35,38,28,39,11,41,11,41,5,42,5,42,5,42, - 5,42,1,42,1,42,114,9,0,0,0, + 25,0,155,0,157,4,166,1,171,0,1,0,144,255,144,255, + 144,255,173,237,100,1,83,0,100,1,83,0,41,8,233,0, + 0,0,0,78,122,18,70,114,111,122,101,110,32,72,101,108, + 108,111,32,87,111,114,108,100,122,8,115,121,115,46,97,114, + 103,118,218,6,99,111,110,102,105,103,41,5,90,12,112,114, + 111,103,114,97,109,95,110,97,109,101,218,10,101,120,101,99, + 117,116,97,98,108,101,90,15,117,115,101,95,101,110,118,105, + 114,111,110,109,101,110,116,90,17,99,111,110,102,105,103,117, + 114,101,95,99,95,115,116,100,105,111,90,14,98,117,102,102, + 101,114,101,100,95,115,116,100,105,111,122,7,99,111,110,102, + 105,103,32,122,2,58,32,41,7,218,3,115,121,115,90,17, + 95,116,101,115,116,105,110,116,101,114,110,97,108,99,97,112, + 105,218,5,112,114,105,110,116,218,4,97,114,103,118,90,11, + 103,101,116,95,99,111,110,102,105,103,115,114,2,0,0,0, + 218,3,107,101,121,169,0,243,0,0,0,0,250,18,116,101, + 115,116,95,102,114,111,122,101,110,109,97,105,110,46,112,121, + 250,8,60,109,111,100,117,108,101,62,114,11,0,0,0,1, + 0,0,0,115,18,0,0,0,2,128,8,3,8,1,12,2, + 16,1,16,1,8,1,28,7,16,249,115,24,0,0,0,2, + 128,8,3,8,1,12,2,16,1,16,1,2,7,4,1,2, + 249,28,7,12,255,4,1,115,114,0,0,0,0,0,1,11, + 1,11,1,11,1,11,1,25,1,25,1,25,1,25,1,6, + 1,6,7,27,1,28,1,28,1,28,1,6,1,6,7,17, + 19,22,19,27,1,28,1,28,1,28,10,39,10,27,10,39, + 10,41,10,41,42,50,10,51,1,7,12,2,1,42,1,42, + 5,8,5,10,5,10,11,41,21,24,11,41,11,41,28,34, + 35,38,28,39,11,41,11,41,5,42,5,42,5,42,12,2, + 12,2,12,2,12,2,12,2,12,2,1,42,1,42,114,9, + 0,0,0, }; diff --git a/Python/ceval.c b/Python/ceval.c index 471bbde46f9db0..544152fd830624 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1378,7 +1378,6 @@ eval_frame_handle_pending(PyThreadState *tstate) /* The stack can grow at most MAXINT deep, as co_nlocals and co_stacksize are ints. */ #define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame))) -#define EMPTY() (STACK_LEVEL() == 0) #define TOP() (stack_pointer[-1]) #define SECOND() (stack_pointer[-2]) #define THIRD() (stack_pointer[-3]) @@ -1390,6 +1389,22 @@ eval_frame_handle_pending(PyThreadState *tstate) #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define BASIC_POP() (*--stack_pointer) +#ifdef Py_DEBUG +#define ASSERT_EMPTY() do { \ + if (STACK_LEVEL()) { \ + fprintf(stderr, "----\n"); \ + while (STACK_LEVEL()) { \ + _PyObject_Dump(BASIC_POP()); \ + fprintf(stderr, "----\n"); \ + } \ + Py_FatalError("Unexpected items on the stack."); \ + } \ +} while (0) +#else +#define ASSERT_EMPTY() ((void)0) +#endif + + #ifdef LLTRACE #define PUSH(v) { (void)(BASIC_PUSH(v), \ lltrace && prtrace(tstate, TOP(), "push")); \ @@ -1434,6 +1449,19 @@ eval_frame_handle_pending(PyThreadState *tstate) #define GET_CACHE() \ _GetSpecializedCacheEntryForInstruction(first_instr, INSTR_OFFSET(), oparg) +#define MAYBE_QUICKEN() \ + do { \ + int err = _Py_IncrementCountAndMaybeQuicken(frame->f_code); \ + if (err) { \ + if (err < 0) { \ + goto error; \ + } \ + /* Update first_instr and next_instr to point to newly quickened code */ \ + int nexti = INSTR_OFFSET(); \ + first_instr = frame->f_code->co_firstinstr; \ + next_instr = first_instr + nexti; \ + } \ + } while (0) #define DEOPT_IF(cond, instname) if (cond) { goto instname ## _miss; } @@ -1734,16 +1762,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr } TARGET(RESUME) { - int err = _Py_IncrementCountAndMaybeQuicken(frame->f_code); - if (err) { - if (err < 0) { - goto error; - } - /* Update first_instr and next_instr to point to newly quickened code */ - int nexti = INSTR_OFFSET(); - first_instr = frame->f_code->co_firstinstr; - next_instr = first_instr + nexti; - } + MAYBE_QUICKEN(); JUMP_TO_INSTRUCTION(RESUME_QUICK); } @@ -2374,7 +2393,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr TARGET(RETURN_VALUE) { PyObject *retval = POP(); - assert(EMPTY()); + ASSERT_EMPTY(); frame->f_state = FRAME_RETURNED; _PyFrame_SetStackPointer(frame, stack_pointer); TRACE_FUNCTION_EXIT(); @@ -4046,16 +4065,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr TARGET(JUMP_ABSOLUTE) { PREDICTED(JUMP_ABSOLUTE); - int err = _Py_IncrementCountAndMaybeQuicken(frame->f_code); - if (err) { - if (err < 0) { - goto error; - } - /* Update first_instr and next_instr to point to newly quickened code */ - int nexti = INSTR_OFFSET(); - first_instr = frame->f_code->co_firstinstr; - next_instr = first_instr + nexti; - } + MAYBE_QUICKEN(); JUMP_TO_INSTRUCTION(JUMP_ABSOLUTE_QUICK); } @@ -4225,6 +4235,39 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr DISPATCH(); } + TARGET(FOR_END) { + /* before: [iter]; after: [iter, iter()] *or* [] */ + MAYBE_QUICKEN(); + JUMP_TO_INSTRUCTION(FOR_END_QUICK); + } + + TARGET(FOR_END_QUICK) { + PREDICTED(FOR_END_QUICK); + PyObject *iter = TOP(); + PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); + if (next != NULL) { + PUSH(next); + JUMPBY(oparg); + CHECK_EVAL_BREAKER(); + PREDICT(STORE_FAST); + PREDICT(UNPACK_SEQUENCE); + DISPATCH(); + } + if (_PyErr_Occurred(tstate)) { + if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { + goto error; + } + else if (tstate->c_tracefunc != NULL) { + call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); + } + _PyErr_Clear(tstate); + } + /* iterator ended normally */ + STACK_SHRINK(1); + Py_DECREF(iter); + DISPATCH(); + } + TARGET(BEFORE_ASYNC_WITH) { PyObject *mgr = TOP(); PyObject *res; @@ -5152,7 +5195,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr if (gen == NULL) { goto error; } - assert(EMPTY()); + ASSERT_EMPTY(); _PyFrame_SetStackPointer(frame, stack_pointer); InterpreterFrame *gen_frame = (InterpreterFrame *)gen->gi_iframe; _PyFrame_Copy(frame, gen_frame); diff --git a/Python/compile.c b/Python/compile.c index 645213b192eaed..6c2baa65420bd2 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -915,6 +915,9 @@ stack_effect(int opcode, int oparg, int jump) case FOR_ITER: /* -1 at end of iterator, 1 if continue iterating. */ return jump > 0 ? -1 : 1; + case FOR_END: + /* -1 at end of iterator, 1 if continue iterating. */ + return jump == 0 ? -1 : 1; case SEND: return jump > 0 ? -1 : 0; case STORE_ATTR: @@ -2970,11 +2973,9 @@ compiler_for(struct compiler *c, stmt_ty s) compiler_use_next_block(c, body); VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); - /* Mark jump as artificial */ - UNSET_LOC(c); - ADDOP_JUMP(c, JUMP_ABSOLUTE, start); + SET_LOC(c, s->v.For.iter); + ADDOP_JUMP(c, FOR_END, body); compiler_use_next_block(c, cleanup); - compiler_pop_fblock(c, FOR_LOOP, start); VISIT_SEQ(c, stmt, s->v.For.orelse); diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index f6cbec75089e5e..aa2a02bd7d4b52 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -57,30 +57,30 @@ static void *opcode_targets[256] = { &&TARGET_CALL_NO_KW_TYPE_1, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, &&TARGET_JUMP_ABSOLUTE_QUICK, + &&TARGET_FOR_END_QUICK, &&TARGET_LOAD_ATTR_ADAPTIVE, - &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_STORE_SUBSCR, &&TARGET_DELETE_SUBSCR, + &&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_GLOBAL_ADAPTIVE, &&TARGET_LOAD_GLOBAL_MODULE, - &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_GET_ITER, &&TARGET_GET_YIELD_FROM_ITER, &&TARGET_PRINT_EXPR, &&TARGET_LOAD_BUILD_CLASS, - &&TARGET_LOAD_METHOD_ADAPTIVE, + &&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_GET_AWAITABLE, &&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_RETURN_GENERATOR, + &&TARGET_LOAD_METHOD_ADAPTIVE, &&TARGET_LOAD_METHOD_CACHED, &&TARGET_LOAD_METHOD_CLASS, &&TARGET_LOAD_METHOD_MODULE, &&TARGET_LOAD_METHOD_NO_DICT, &&TARGET_RESUME_QUICK, - &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_LIST_TO_TUPLE, &&TARGET_RETURN_VALUE, &&TARGET_IMPORT_STAR, @@ -130,7 +130,7 @@ static void *opcode_targets[256] = { &&TARGET_POP_JUMP_IF_NOT_NONE, &&TARGET_POP_JUMP_IF_NONE, &&TARGET_RAISE_VARARGS, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, + &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_MAKE_FUNCTION, &&TARGET_BUILD_SLICE, &&TARGET_JUMP_NO_INTERRUPT, @@ -139,40 +139,40 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_UNPACK_SEQUENCE_ADAPTIVE, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, &&TARGET_LOAD_CLASSDEREF, &&TARGET_COPY_FREE_VARS, - &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_UNPACK_SEQUENCE_ADAPTIVE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, + &&TARGET_UNPACK_SEQUENCE_LIST, &&TARGET_UNPACK_SEQUENCE_TUPLE, - &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, + &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_LOAD_FAST__LOAD_FAST, - &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_LOAD_METHOD, - &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, &&TARGET_PRECALL, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_CALL, &&TARGET_KW_NAMES, - &&_unknown_opcode, + &&TARGET_FOR_END, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, diff --git a/Python/specialize.c b/Python/specialize.c index 7dd12c7de2aeb6..c0b44e210d21c3 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -415,6 +415,9 @@ optimize(SpecializedCacheOrInstruction *quickened, int len) case JUMP_ABSOLUTE: instructions[i] = _Py_MAKECODEUNIT(JUMP_ABSOLUTE_QUICK, oparg); break; + case FOR_END: + instructions[i] = _Py_MAKECODEUNIT(FOR_END_QUICK, oparg); + break; case RESUME: instructions[i] = _Py_MAKECODEUNIT(RESUME_QUICK, oparg); break; From 4178c30b3533b1f57a0b9f713131db5881c7771d Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 20 Feb 2022 02:12:03 -0500 Subject: [PATCH 02/21] Use jabs, not jrel --- Include/opcode.h | 2 +- Lib/opcode.py | 2 +- Python/ceval.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index 9913d7d311e13e..0fdc5cfd260df5 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -188,7 +188,7 @@ static uint32_t _PyOpcode_RelativeJump[8] = { 536870912U, 134234112U, 0U, - 8192U, + 0U, 0U, 0U, }; diff --git a/Lib/opcode.py b/Lib/opcode.py index ff84b78b25014a..7c3b423126f72a 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -194,7 +194,7 @@ def jabs_op(name, op): def_op('KW_NAMES', 172) hasconst.append(172) -jrel_op('FOR_END', 173) +jabs_op('FOR_END', 173) del def_op, name_op, jrel_op, jabs_op diff --git a/Python/ceval.c b/Python/ceval.c index 544152fd830624..97c7e88f3004bb 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4247,7 +4247,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next != NULL) { PUSH(next); - JUMPBY(oparg); + JUMPTO(oparg); CHECK_EVAL_BREAKER(); PREDICT(STORE_FAST); PREDICT(UNPACK_SEQUENCE); From 245b43fb2a06fb69bfc5b37ccfc7607a498282e2 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 20 Feb 2022 05:30:05 -0500 Subject: [PATCH 03/21] Bump magic --- Lib/importlib/_bootstrap_external.py | 2 +- Programs/test_frozenmain.h | 61 ++++++++++++++-------------- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index f704f805786605..1756eac0043fb0 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -403,7 +403,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3485).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3487).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 848845739004bc..4f0fd1c0ddf0b7 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,39 +1,38 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, - 0,0,0,0,0,115,114,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,115,108,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, 100,2,166,1,171,0,1,0,2,0,101,2,100,3,101,0, 106,3,166,2,171,0,1,0,2,0,101,1,106,4,166,0, - 171,0,100,4,25,0,90,5,100,5,68,0,93,21,90,6, + 171,0,100,4,25,0,90,5,100,5,68,0,93,18,90,6, 2,0,101,2,100,6,101,6,155,0,100,7,101,5,101,6, - 25,0,155,0,157,4,166,1,171,0,1,0,144,255,144,255, - 144,255,173,237,100,1,83,0,100,1,83,0,41,8,233,0, - 0,0,0,78,122,18,70,114,111,122,101,110,32,72,101,108, - 108,111,32,87,111,114,108,100,122,8,115,121,115,46,97,114, - 103,118,218,6,99,111,110,102,105,103,41,5,90,12,112,114, - 111,103,114,97,109,95,110,97,109,101,218,10,101,120,101,99, - 117,116,97,98,108,101,90,15,117,115,101,95,101,110,118,105, - 114,111,110,109,101,110,116,90,17,99,111,110,102,105,103,117, - 114,101,95,99,95,115,116,100,105,111,90,14,98,117,102,102, - 101,114,101,100,95,115,116,100,105,111,122,7,99,111,110,102, - 105,103,32,122,2,58,32,41,7,218,3,115,121,115,90,17, - 95,116,101,115,116,105,110,116,101,114,110,97,108,99,97,112, - 105,218,5,112,114,105,110,116,218,4,97,114,103,118,90,11, - 103,101,116,95,99,111,110,102,105,103,115,114,2,0,0,0, - 218,3,107,101,121,169,0,243,0,0,0,0,250,18,116,101, - 115,116,95,102,114,111,122,101,110,109,97,105,110,46,112,121, - 250,8,60,109,111,100,117,108,101,62,114,11,0,0,0,1, - 0,0,0,115,18,0,0,0,2,128,8,3,8,1,12,2, - 16,1,16,1,8,1,28,7,16,249,115,24,0,0,0,2, - 128,8,3,8,1,12,2,16,1,16,1,2,7,4,1,2, - 249,28,7,12,255,4,1,115,114,0,0,0,0,0,1,11, - 1,11,1,11,1,11,1,25,1,25,1,25,1,25,1,6, - 1,6,7,27,1,28,1,28,1,28,1,6,1,6,7,17, - 19,22,19,27,1,28,1,28,1,28,10,39,10,27,10,39, - 10,41,10,41,42,50,10,51,1,7,12,2,1,42,1,42, - 5,8,5,10,5,10,11,41,21,24,11,41,11,41,28,34, - 35,38,28,39,11,41,11,41,5,42,5,42,5,42,12,2, - 12,2,12,2,12,2,12,2,12,2,1,42,1,42,114,9, - 0,0,0, + 25,0,155,0,157,4,166,1,171,0,1,0,173,34,100,1, + 83,0,100,1,83,0,41,8,233,0,0,0,0,78,122,18, + 70,114,111,122,101,110,32,72,101,108,108,111,32,87,111,114, + 108,100,122,8,115,121,115,46,97,114,103,118,218,6,99,111, + 110,102,105,103,41,5,90,12,112,114,111,103,114,97,109,95, + 110,97,109,101,218,10,101,120,101,99,117,116,97,98,108,101, + 90,15,117,115,101,95,101,110,118,105,114,111,110,109,101,110, + 116,90,17,99,111,110,102,105,103,117,114,101,95,99,95,115, + 116,100,105,111,90,14,98,117,102,102,101,114,101,100,95,115, + 116,100,105,111,122,7,99,111,110,102,105,103,32,122,2,58, + 32,41,7,218,3,115,121,115,90,17,95,116,101,115,116,105, + 110,116,101,114,110,97,108,99,97,112,105,218,5,112,114,105, + 110,116,218,4,97,114,103,118,90,11,103,101,116,95,99,111, + 110,102,105,103,115,114,2,0,0,0,218,3,107,101,121,169, + 0,243,0,0,0,0,250,18,116,101,115,116,95,102,114,111, + 122,101,110,109,97,105,110,46,112,121,250,8,60,109,111,100, + 117,108,101,62,114,11,0,0,0,1,0,0,0,115,18,0, + 0,0,2,128,8,3,8,1,12,2,16,1,16,1,8,1, + 28,7,10,249,115,24,0,0,0,2,128,8,3,8,1,12, + 2,16,1,16,1,2,7,4,1,2,249,28,7,6,255,4, + 1,115,108,0,0,0,0,0,1,11,1,11,1,11,1,11, + 1,25,1,25,1,25,1,25,1,6,1,6,7,27,1,28, + 1,28,1,28,1,6,1,6,7,17,19,22,19,27,1,28, + 1,28,1,28,10,39,10,27,10,39,10,41,10,41,42,50, + 10,51,1,7,12,2,1,42,1,42,5,8,5,10,5,10, + 11,41,21,24,11,41,11,41,28,34,35,38,28,39,11,41, + 11,41,5,42,5,42,5,42,12,2,12,2,12,2,1,42, + 1,42,114,9,0,0,0, }; From 8f3cd5a1dc1a6c0a38889c914b7c7c8df2a10b5c Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 20 Mar 2022 02:15:04 -0400 Subject: [PATCH 04/21] Remove FOR_ITER entirely --- Include/opcode.h | 37 ++++++++------- Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 1 - Lib/test/test__opcode.py | 6 +-- Objects/frameobject.c | 4 +- Programs/test_frozenmain.h | 67 ++++++++++++++-------------- Python/ceval.c | 40 +++-------------- Python/compile.c | 34 ++++++++------ Python/opcode_targets.h | 18 ++++---- 9 files changed, 93 insertions(+), 116 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index 7f005bb019846d..3c06ea1fe6f1a4 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -47,7 +47,6 @@ extern "C" { #define STORE_NAME 90 #define DELETE_NAME 91 #define UNPACK_SEQUENCE 92 -#define FOR_ITER 93 #define UNPACK_EX 94 #define STORE_ATTR 95 #define DELETE_ATTR 96 @@ -169,22 +168,22 @@ extern "C" { #define PRECALL_NO_KW_TUPLE_1 79 #define PRECALL_NO_KW_TYPE_1 80 #define PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST 81 -#define PRECALL_BOUND_METHOD 140 -#define PRECALL_PYFUNC 141 -#define RESUME_QUICK 143 -#define STORE_ATTR_ADAPTIVE 150 -#define STORE_ATTR_INSTANCE_VALUE 153 -#define STORE_ATTR_SLOT 154 -#define STORE_ATTR_WITH_HINT 158 -#define UNPACK_SEQUENCE_ADAPTIVE 159 -#define UNPACK_SEQUENCE_LIST 161 -#define UNPACK_SEQUENCE_TUPLE 167 -#define UNPACK_SEQUENCE_TWO_TUPLE 168 -#define LOAD_FAST__LOAD_FAST 169 -#define STORE_FAST__LOAD_FAST 170 -#define LOAD_FAST__LOAD_CONST 174 -#define LOAD_CONST__LOAD_FAST 175 -#define STORE_FAST__STORE_FAST 176 +#define PRECALL_BOUND_METHOD 93 +#define PRECALL_PYFUNC 140 +#define RESUME_QUICK 141 +#define STORE_ATTR_ADAPTIVE 143 +#define STORE_ATTR_INSTANCE_VALUE 150 +#define STORE_ATTR_SLOT 153 +#define STORE_ATTR_WITH_HINT 154 +#define UNPACK_SEQUENCE_ADAPTIVE 158 +#define UNPACK_SEQUENCE_LIST 159 +#define UNPACK_SEQUENCE_TUPLE 161 +#define UNPACK_SEQUENCE_TWO_TUPLE 167 +#define LOAD_FAST__LOAD_FAST 168 +#define STORE_FAST__LOAD_FAST 169 +#define LOAD_FAST__LOAD_CONST 170 +#define LOAD_CONST__LOAD_FAST 174 +#define STORE_FAST__STORE_FAST 175 #define DO_TRACING 255 extern const uint8_t _PyOpcode_InlineCacheEntries[256]; @@ -193,7 +192,7 @@ extern const uint8_t _PyOpcode_InlineCacheEntries[256]; static const uint32_t _PyOpcode_RelativeJump[8] = { 0U, 0U, - 536870912U, + 0U, 134234112U, 0U, 0U, @@ -203,7 +202,7 @@ static const uint32_t _PyOpcode_RelativeJump[8] = { static const uint32_t _PyOpcode_Jump[8] = { 0U, 0U, - 536870912U, + 0U, 2316288000U, 67U, 8192U, diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 40873c2882a65d..2f5fada1a8fec5 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -410,7 +410,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3490).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3493).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py index 32ed667778350f..01c552d3431fd0 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -109,7 +109,6 @@ def jabs_op(name, op, entries=0): name_op('STORE_NAME', 90) # Index in name list name_op('DELETE_NAME', 91) # "" def_op('UNPACK_SEQUENCE', 92, 1) # Number of tuple items -jrel_op('FOR_ITER', 93) def_op('UNPACK_EX', 94) name_op('STORE_ATTR', 95, 4) # Index in name list name_op('DELETE_ATTR', 96) # "" diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index 7c1c0cfdb069b8..64cf7b36b05dd1 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -37,10 +37,10 @@ def test_stack_effect_jump(self): self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0), 0) self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=True), 0) self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=False), -1) - FOR_ITER = dis.opmap['FOR_ITER'] + FOR_ITER = dis.opmap['FOR_END'] self.assertEqual(stack_effect(FOR_ITER, 0), 1) - self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), -1) - self.assertEqual(stack_effect(FOR_ITER, 0, jump=False), 1) + self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), 1) + self.assertEqual(stack_effect(FOR_ITER, 0, jump=False), -1) JUMP_FORWARD = dis.opmap['JUMP_FORWARD'] self.assertEqual(stack_effect(JUMP_FORWARD, 0), 0) self.assertEqual(stack_effect(JUMP_FORWARD, 0, jump=True), 0) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 73b6c3d9f8ab77..5186b548f9f2e7 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -264,11 +264,11 @@ mark_stacks(PyCodeObject *code_obj, int len) next_stack = push_value(pop_value(next_stack), Iterator); stacks[i+1] = next_stack; break; - case FOR_ITER: + case FOR_END: { int64_t target_stack = pop_value(next_stack); stacks[i+1] = push_value(next_stack, Object); - j = get_arg(code, i) + i + 1; + j = get_arg(code, i); assert(j < len); assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack); stacks[j] = target_stack; diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 830c1826a71153..20a0043c09c739 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -1,7 +1,7 @@ // Auto-generated by Programs/freeze_test_frozenmain.py unsigned char M_test_frozenmain[] = { 227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0, - 0,0,0,0,0,115,180,0,0,0,151,0,100,0,100,1, + 0,0,0,0,0,115,176,0,0,0,151,0,100,0,100,1, 108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2, 100,2,166,1,0,0,171,1,0,0,0,0,0,0,0,0, 1,0,2,0,101,2,100,3,101,0,106,3,0,0,0,0, @@ -9,39 +9,38 @@ unsigned char M_test_frozenmain[] = { 0,0,1,0,2,0,101,1,106,4,0,0,0,0,0,0, 0,0,166,0,0,0,171,0,0,0,0,0,0,0,0,0, 100,4,25,0,0,0,0,0,0,0,0,0,90,5,100,5, - 68,0,93,27,90,6,2,0,101,2,100,6,101,6,155,0, + 68,0,110,24,90,6,2,0,101,2,100,6,101,6,155,0, 100,7,101,5,101,6,25,0,0,0,0,0,0,0,0,0, 155,0,157,4,166,1,0,0,171,1,0,0,0,0,0,0, - 0,0,1,0,173,61,100,1,83,0,100,1,83,0,41,8, - 233,0,0,0,0,78,122,18,70,114,111,122,101,110,32,72, - 101,108,108,111,32,87,111,114,108,100,122,8,115,121,115,46, - 97,114,103,118,218,6,99,111,110,102,105,103,41,5,90,12, - 112,114,111,103,114,97,109,95,110,97,109,101,218,10,101,120, - 101,99,117,116,97,98,108,101,90,15,117,115,101,95,101,110, - 118,105,114,111,110,109,101,110,116,90,17,99,111,110,102,105, - 103,117,114,101,95,99,95,115,116,100,105,111,90,14,98,117, - 102,102,101,114,101,100,95,115,116,100,105,111,122,7,99,111, - 110,102,105,103,32,122,2,58,32,41,7,218,3,115,121,115, - 90,17,95,116,101,115,116,105,110,116,101,114,110,97,108,99, - 97,112,105,218,5,112,114,105,110,116,218,4,97,114,103,118, - 90,11,103,101,116,95,99,111,110,102,105,103,115,114,2,0, - 0,0,218,3,107,101,121,169,0,243,0,0,0,0,250,18, - 116,101,115,116,95,102,114,111,122,101,110,109,97,105,110,46, - 112,121,250,8,60,109,111,100,117,108,101,62,114,11,0,0, - 0,1,0,0,0,115,18,0,0,0,2,128,8,3,8,1, - 22,2,34,1,42,1,8,1,46,7,10,249,115,24,0,0, - 0,2,128,8,3,8,1,22,2,34,1,42,1,2,7,4, - 1,2,249,46,7,6,255,4,1,115,180,0,0,0,0,0, - 1,11,1,11,1,11,1,11,1,25,1,25,1,25,1,25, - 1,6,1,6,7,27,1,28,1,28,1,28,1,28,1,28, - 1,28,1,28,1,28,1,6,1,6,7,17,19,22,19,27, - 19,27,19,27,19,27,19,27,1,28,1,28,1,28,1,28, - 1,28,1,28,1,28,1,28,10,39,10,27,10,39,10,39, - 10,39,10,39,10,39,10,41,10,41,10,41,10,41,10,41, - 10,41,10,41,42,50,10,51,10,51,10,51,10,51,10,51, - 1,7,12,2,1,42,1,42,5,8,5,10,5,10,11,41, - 21,24,11,41,11,41,28,34,35,38,28,39,28,39,28,39, - 28,39,28,39,11,41,11,41,5,42,5,42,5,42,5,42, - 5,42,5,42,5,42,5,42,12,2,12,2,12,2,1,42, - 1,42,114,9,0,0,0, + 0,0,1,0,173,61,100,1,83,0,41,8,233,0,0,0, + 0,78,122,18,70,114,111,122,101,110,32,72,101,108,108,111, + 32,87,111,114,108,100,122,8,115,121,115,46,97,114,103,118, + 218,6,99,111,110,102,105,103,41,5,90,12,112,114,111,103, + 114,97,109,95,110,97,109,101,218,10,101,120,101,99,117,116, + 97,98,108,101,90,15,117,115,101,95,101,110,118,105,114,111, + 110,109,101,110,116,90,17,99,111,110,102,105,103,117,114,101, + 95,99,95,115,116,100,105,111,90,14,98,117,102,102,101,114, + 101,100,95,115,116,100,105,111,122,7,99,111,110,102,105,103, + 32,122,2,58,32,41,7,218,3,115,121,115,90,17,95,116, + 101,115,116,105,110,116,101,114,110,97,108,99,97,112,105,218, + 5,112,114,105,110,116,218,4,97,114,103,118,90,11,103,101, + 116,95,99,111,110,102,105,103,115,114,2,0,0,0,218,3, + 107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116, + 95,102,114,111,122,101,110,109,97,105,110,46,112,121,250,8, + 60,109,111,100,117,108,101,62,114,11,0,0,0,1,0,0, + 0,115,18,0,0,0,2,128,8,3,8,1,22,2,34,1, + 42,1,8,1,46,7,6,249,115,22,0,0,0,2,128,8, + 3,8,1,22,2,34,1,42,1,2,7,4,1,2,249,46, + 7,6,255,115,176,0,0,0,0,0,1,11,1,11,1,11, + 1,11,1,25,1,25,1,25,1,25,1,6,1,6,7,27, + 1,28,1,28,1,28,1,28,1,28,1,28,1,28,1,28, + 1,6,1,6,7,17,19,22,19,27,19,27,19,27,19,27, + 19,27,1,28,1,28,1,28,1,28,1,28,1,28,1,28, + 1,28,10,39,10,27,10,39,10,39,10,39,10,39,10,39, + 10,41,10,41,10,41,10,41,10,41,10,41,10,41,42,50, + 10,51,10,51,10,51,10,51,10,51,1,7,12,2,1,42, + 1,42,5,8,5,10,5,10,11,41,21,24,11,41,11,41, + 28,34,35,38,28,39,28,39,28,39,28,39,28,39,11,41, + 11,41,5,42,5,42,5,42,5,42,5,42,5,42,5,42, + 5,42,12,2,12,2,12,2,114,9,0,0,0, }; diff --git a/Python/ceval.c b/Python/ceval.c index 54db06acade168..794d3b08101e0f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3953,6 +3953,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int } TARGET(JUMP_FORWARD) { + PREDICTED(JUMP_FORWARD); JUMPBY(oparg); DISPATCH(); } @@ -4191,7 +4192,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int SET_TOP(iter); if (iter == NULL) goto error; - PREDICT(FOR_ITER); + PREDICT(JUMP_FORWARD); DISPATCH(); } @@ -4224,38 +4225,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int DISPATCH(); } - TARGET(FOR_ITER) { - PREDICTED(FOR_ITER); - /* before: [iter]; after: [iter, iter()] *or* [] */ - PyObject *iter = TOP(); -#ifdef Py_STATS - extern int _PySpecialization_ClassifyIterator(PyObject *); - _py_stats.opcode_stats[FOR_ITER].specialization.failure++; - _py_stats.opcode_stats[FOR_ITER].specialization.failure_kinds[_PySpecialization_ClassifyIterator(iter)]++; -#endif - PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); - if (next != NULL) { - PUSH(next); - PREDICT(STORE_FAST); - PREDICT(UNPACK_SEQUENCE); - DISPATCH(); - } - if (_PyErr_Occurred(tstate)) { - if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) { - goto error; - } - else if (tstate->c_tracefunc != NULL) { - call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame); - } - _PyErr_Clear(tstate); - } - /* iterator ended normally */ - STACK_SHRINK(1); - Py_DECREF(iter); - JUMPBY(oparg); - DISPATCH(); - } - TARGET(FOR_END) { /* before: [iter]; after: [iter, iter()] *or* [] */ MAYBE_QUICKEN(); @@ -4265,6 +4234,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int TARGET(FOR_END_QUICK) { PREDICTED(FOR_END_QUICK); PyObject *iter = TOP(); +#ifdef Py_STATS + extern int _PySpecialization_ClassifyIterator(PyObject *); + _py_stats.opcode_stats[FOR_END].specialization.failure++; + _py_stats.opcode_stats[FOR_END].specialization.failure_kinds[_PySpecialization_ClassifyIterator(iter)]++; +#endif PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next != NULL) { PUSH(next); diff --git a/Python/compile.c b/Python/compile.c index b8b3126e269623..25ea3bb80234f7 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -942,9 +942,6 @@ stack_effect(int opcode, int oparg, int jump) return oparg-1; case UNPACK_EX: return (oparg&0xFF) + (oparg>>8); - case FOR_ITER: - /* -1 at end of iterator, 1 if continue iterating. */ - return jump > 0 ? -1 : 1; case FOR_END: /* -1 at end of iterator, 1 if continue iterating. */ return jump == 0 ? -1 : 1; @@ -2999,13 +2996,16 @@ compiler_if(struct compiler *c, stmt_ty s) static int compiler_for(struct compiler *c, stmt_ty s) { - basicblock *start, *body, *cleanup, *end; + basicblock *start, *body, *cleanup, *end, *back_jump; start = compiler_new_block(c); body = compiler_new_block(c); cleanup = compiler_new_block(c); + back_jump = compiler_new_block(c); end = compiler_new_block(c); - if (start == NULL || body == NULL || end == NULL || cleanup == NULL) { + if (start == NULL || body == NULL || end == NULL || + cleanup == NULL || back_jump == NULL) + { return 0; } if (!compiler_push_fblock(c, FOR_LOOP, start, end, NULL)) { @@ -3014,10 +3014,11 @@ compiler_for(struct compiler *c, stmt_ty s) VISIT(c, expr, s->v.For.iter); ADDOP(c, GET_ITER); compiler_use_next_block(c, start); - ADDOP_JUMP(c, FOR_ITER, cleanup); + ADDOP_JUMP(c, JUMP_FORWARD, back_jump); compiler_use_next_block(c, body); VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); + compiler_use_next_block(c, back_jump); SET_LOC(c, s->v.For.iter); ADDOP_JUMP(c, FOR_END, body); compiler_use_next_block(c, cleanup); @@ -5066,14 +5067,15 @@ compiler_sync_comprehension_generator(struct compiler *c, and then write to the element */ comprehension_ty gen; - basicblock *start, *anchor, *if_cleanup; + basicblock *start, *anchor, *if_cleanup, *body; Py_ssize_t i, n; start = compiler_new_block(c); if_cleanup = compiler_new_block(c); anchor = compiler_new_block(c); + body = compiler_new_block(c); - if (start == NULL || if_cleanup == NULL || anchor == NULL) { + if (start == NULL || if_cleanup == NULL || anchor == NULL || body == NULL) { return 0; } @@ -5115,7 +5117,8 @@ compiler_sync_comprehension_generator(struct compiler *c, if (start) { depth++; compiler_use_next_block(c, start); - ADDOP_JUMP(c, FOR_ITER, anchor); + ADDOP_JUMP(c, JUMP_FORWARD, if_cleanup); + compiler_use_next_block(c, body); } VISIT(c, expr, gen->target); @@ -5163,7 +5166,8 @@ compiler_sync_comprehension_generator(struct compiler *c, } compiler_use_next_block(c, if_cleanup); if (start) { - ADDOP_JUMP(c, JUMP_ABSOLUTE, start); + SET_LOC(c, gen->iter); + ADDOP_JUMP(c, FOR_END, body); compiler_use_next_block(c, anchor); } @@ -8800,9 +8804,11 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) i -= jump_thread(inst, target, JUMP_ABSOLUTE); } break; - case FOR_ITER: - if (target->i_opcode == JUMP_FORWARD) { - i -= jump_thread(inst, target, FOR_ITER); + case FOR_END: + switch (target->i_opcode) { + case JUMP_ABSOLUTE: + case JUMP_FORWARD: + i -= jump_thread(inst, target, FOR_END); } break; case SWAP: @@ -8932,7 +8938,7 @@ normalize_basic_block(basicblock *bb) { case POP_JUMP_IF_TRUE: case JUMP_IF_FALSE_OR_POP: case JUMP_IF_TRUE_OR_POP: - case FOR_ITER: + case FOR_END: if (i != bb->b_iused-1) { PyErr_SetString(PyExc_SystemError, "malformed control flow graph."); return -1; diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index fa5ce2e52fc2e4..a1151e76f58d4e 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -92,7 +92,7 @@ static void *opcode_targets[256] = { &&TARGET_STORE_NAME, &&TARGET_DELETE_NAME, &&TARGET_UNPACK_SEQUENCE, - &&TARGET_FOR_ITER, + &&TARGET_PRECALL_BOUND_METHOD, &&TARGET_UNPACK_EX, &&TARGET_STORE_ATTR, &&TARGET_DELETE_ATTR, @@ -139,41 +139,40 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, - &&TARGET_PRECALL_BOUND_METHOD, &&TARGET_PRECALL_PYFUNC, - &&TARGET_CALL_FUNCTION_EX, &&TARGET_RESUME_QUICK, + &&TARGET_CALL_FUNCTION_EX, + &&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, &&TARGET_LOAD_CLASSDEREF, &&TARGET_COPY_FREE_VARS, - &&TARGET_STORE_ATTR_ADAPTIVE, + &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_RESUME, &&TARGET_MATCH_CLASS, - &&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_SLOT, + &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_FORMAT_VALUE, &&TARGET_BUILD_CONST_KEY_MAP, &&TARGET_BUILD_STRING, - &&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_UNPACK_SEQUENCE_ADAPTIVE, - &&TARGET_LOAD_METHOD, &&TARGET_UNPACK_SEQUENCE_LIST, + &&TARGET_LOAD_METHOD, + &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_LIST_EXTEND, &&TARGET_SET_UPDATE, &&TARGET_DICT_MERGE, &&TARGET_DICT_UPDATE, &&TARGET_PRECALL, - &&TARGET_UNPACK_SEQUENCE_TUPLE, &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_STORE_FAST__LOAD_FAST, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_CALL, &&TARGET_KW_NAMES, &&TARGET_FOR_END, - &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_STORE_FAST__STORE_FAST, &&_unknown_opcode, @@ -254,5 +253,6 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_DO_TRACING }; From 4520a5aa3848c557d22fba767fdbb0e28d4f520c Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 20 Mar 2022 03:05:29 -0400 Subject: [PATCH 05/21] Fix some failng tests --- Lib/test/test__opcode.py | 8 ++++---- Lib/test/test_peepholer.py | 8 ++++---- Python/compile.c | 1 - 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py index 64cf7b36b05dd1..2854a960b154ea 100644 --- a/Lib/test/test__opcode.py +++ b/Lib/test/test__opcode.py @@ -37,10 +37,10 @@ def test_stack_effect_jump(self): self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0), 0) self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=True), 0) self.assertEqual(stack_effect(JUMP_IF_TRUE_OR_POP, 0, jump=False), -1) - FOR_ITER = dis.opmap['FOR_END'] - self.assertEqual(stack_effect(FOR_ITER, 0), 1) - self.assertEqual(stack_effect(FOR_ITER, 0, jump=True), 1) - self.assertEqual(stack_effect(FOR_ITER, 0, jump=False), -1) + FOR_END = dis.opmap['FOR_END'] + self.assertEqual(stack_effect(FOR_END, 0), 1) + self.assertEqual(stack_effect(FOR_END, 0, jump=True), 1) + self.assertEqual(stack_effect(FOR_END, 0, jump=False), -1) JUMP_FORWARD = dis.opmap['JUMP_FORWARD'] self.assertEqual(stack_effect(JUMP_FORWARD, 0), 0) self.assertEqual(stack_effect(JUMP_FORWARD, 0, jump=True), 0) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 6f24b291b00b59..d40f982fcd0e30 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -509,16 +509,16 @@ def f(x): def test_assignment_idiom_in_comprehensions(self): def listcomp(): return [y for x in a for y in [f(x)]] - self.assertEqual(count_instr_recursively(listcomp, 'FOR_ITER'), 1) + self.assertEqual(count_instr_recursively(listcomp, 'FOR_END'), 1) def setcomp(): return {y for x in a for y in [f(x)]} - self.assertEqual(count_instr_recursively(setcomp, 'FOR_ITER'), 1) + self.assertEqual(count_instr_recursively(setcomp, 'FOR_END'), 1) def dictcomp(): return {y: y for x in a for y in [f(x)]} - self.assertEqual(count_instr_recursively(dictcomp, 'FOR_ITER'), 1) + self.assertEqual(count_instr_recursively(dictcomp, 'FOR_END'), 1) def genexpr(): return (y for x in a for y in [f(x)]) - self.assertEqual(count_instr_recursively(genexpr, 'FOR_ITER'), 1) + self.assertEqual(count_instr_recursively(genexpr, 'FOR_END'), 1) def test_format_combinations(self): flags = '-+ #0' diff --git a/Python/compile.c b/Python/compile.c index 25ea3bb80234f7..55801f443cf048 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5166,7 +5166,6 @@ compiler_sync_comprehension_generator(struct compiler *c, } compiler_use_next_block(c, if_cleanup); if (start) { - SET_LOC(c, gen->iter); ADDOP_JUMP(c, FOR_END, body); compiler_use_next_block(c, anchor); } From 6284f20eba1c24918a0bdc0e5b1bf570bac69f6d Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 20 Mar 2022 03:41:20 -0400 Subject: [PATCH 06/21] exclude test_frozenmain --- Programs/test_frozenmain | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 Programs/test_frozenmain diff --git a/Programs/test_frozenmain b/Programs/test_frozenmain deleted file mode 100644 index e7e323d2986758..00000000000000 --- a/Programs/test_frozenmain +++ /dev/null @@ -1,27 +0,0 @@ -// Auto-generated by Programs/freeze_test_frozenmain.py -unsigned char M_test_frozenmain[] = { - 227,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,7,0,0,0,64,0,0,0,115,86,0,0,0,100,0, - 100,1,108,0,90,0,100,0,100,1,108,1,90,1,101,2, - 100,2,131,1,1,0,101,2,100,3,101,0,106,3,131,2, - 1,0,101,1,160,4,161,0,100,4,25,0,90,5,100,5, - 68,0,93,14,90,6,101,2,100,6,101,6,155,0,100,7, - 101,5,101,6,25,0,155,0,157,4,131,1,1,0,113,26, - 100,1,83,0,41,8,233,0,0,0,0,78,122,18,70,114, - 111,122,101,110,32,72,101,108,108,111,32,87,111,114,108,100, - 122,8,115,121,115,46,97,114,103,118,218,6,99,111,110,102, - 105,103,41,5,90,12,112,114,111,103,114,97,109,95,110,97, - 109,101,218,10,101,120,101,99,117,116,97,98,108,101,90,15, - 117,115,101,95,101,110,118,105,114,111,110,109,101,110,116,90, - 17,99,111,110,102,105,103,117,114,101,95,99,95,115,116,100, - 105,111,90,14,98,117,102,102,101,114,101,100,95,115,116,100, - 105,111,122,7,99,111,110,102,105,103,32,122,2,58,32,41, - 7,218,3,115,121,115,90,17,95,116,101,115,116,105,110,116, - 101,114,110,97,108,99,97,112,105,218,5,112,114,105,110,116, - 218,4,97,114,103,118,90,11,103,101,116,95,99,111,110,102, - 105,103,115,114,2,0,0,0,218,3,107,101,121,169,0,114, - 8,0,0,0,114,8,0,0,0,250,18,116,101,115,116,95, - 102,114,111,122,101,110,109,97,105,110,46,112,121,218,8,60, - 109,111,100,117,108,101,62,1,0,0,0,115,16,0,0,0, - 8,3,8,1,8,2,12,1,12,1,8,1,26,7,4,249, -}; From 3b328e7584b447c85a53df80c111caffe83252a6 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Thu, 24 Mar 2022 00:26:09 -0400 Subject: [PATCH 07/21] fix some tracing tests --- Python/ceval.c | 11 +++++++---- Python/compile.c | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 64f35e7fa34748..f1f8df25221112 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -6762,11 +6762,14 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, } if (line != -1 && f->f_trace_lines) { /* Trace backward edges (except in 'yield from') or if line number has changed */ + // SEND has no quickened forms, so no need to use _PyOpcode_Deopt here. + int opcode1 = _Py_OPCODE(_PyCode_CODE(frame->f_code)[frame->f_lasti]); + int opcode2 = _Py_OPCODE(_PyCode_CODE(frame->f_code)[instr_prev]); + int trace = line != lastline || - (frame->f_lasti < instr_prev && - // SEND has no quickened forms, so no need to use _PyOpcode_Deopt - // here: - _Py_OPCODE(_PyCode_CODE(frame->f_code)[frame->f_lasti]) != SEND); + (frame->f_lasti < instr_prev && opcode1 != SEND && + opcode2 != FOR_END && opcode2 != FOR_END_QUICK); + if (trace) { result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } diff --git a/Python/compile.c b/Python/compile.c index 090fded31660d8..5634f5ddf622a5 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -3014,7 +3014,7 @@ compiler_for(struct compiler *c, stmt_ty s) VISIT(c, expr, s->v.For.iter); ADDOP(c, GET_ITER); compiler_use_next_block(c, start); - ADDOP_JUMP(c, JUMP_FORWARD, back_jump); + ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, back_jump); compiler_use_next_block(c, body); VISIT(c, expr, s->v.For.target); VISIT_SEQ(c, stmt, s->v.For.body); @@ -5117,7 +5117,7 @@ compiler_sync_comprehension_generator(struct compiler *c, if (start) { depth++; compiler_use_next_block(c, start); - ADDOP_JUMP(c, JUMP_FORWARD, if_cleanup); + ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, if_cleanup); compiler_use_next_block(c, body); } VISIT(c, expr, gen->target); From bdd7f07af5bc70044d585bc5f2f8b3e7950d3ca3 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Thu, 24 Mar 2022 15:57:13 -0400 Subject: [PATCH 08/21] fix swap pop/push in frameobject.c --- Objects/frameobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index af87218a793aca..850bcfd60d2c36 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -271,8 +271,8 @@ mark_stacks(PyCodeObject *code_obj, int len) break; case FOR_END: { - int64_t target_stack = pop_value(next_stack); - stacks[i+1] = push_value(next_stack, Object); + int64_t target_stack = push_value(next_stack, Object); + stacks[i+1] = pop_value(next_stack); j = get_arg(code, i); assert(j < len); assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack); From 77d52e69653506ea39599dd8c54fc0e9f7772f51 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 00:38:58 -0400 Subject: [PATCH 09/21] Get test.test_trace passing --- Programs/test_frozenmain.h | 30 +++++++++++++++--------------- Python/ceval.c | 17 ++++++++++++----- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 20a0043c09c739..23b847159579c0 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -28,19 +28,19 @@ unsigned char M_test_frozenmain[] = { 107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116, 95,102,114,111,122,101,110,109,97,105,110,46,112,121,250,8, 60,109,111,100,117,108,101,62,114,11,0,0,0,1,0,0, - 0,115,18,0,0,0,2,128,8,3,8,1,22,2,34,1, - 42,1,8,1,46,7,6,249,115,22,0,0,0,2,128,8, - 3,8,1,22,2,34,1,42,1,2,7,4,1,2,249,46, - 7,6,255,115,176,0,0,0,0,0,1,11,1,11,1,11, - 1,11,1,25,1,25,1,25,1,25,1,6,1,6,7,27, - 1,28,1,28,1,28,1,28,1,28,1,28,1,28,1,28, - 1,6,1,6,7,17,19,22,19,27,19,27,19,27,19,27, - 19,27,1,28,1,28,1,28,1,28,1,28,1,28,1,28, - 1,28,10,39,10,27,10,39,10,39,10,39,10,39,10,39, - 10,41,10,41,10,41,10,41,10,41,10,41,10,41,42,50, - 10,51,10,51,10,51,10,51,10,51,1,7,12,2,1,42, - 1,42,5,8,5,10,5,10,11,41,21,24,11,41,11,41, - 28,34,35,38,28,39,28,39,28,39,28,39,28,39,11,41, - 11,41,5,42,5,42,5,42,5,42,5,42,5,42,5,42, - 5,42,12,2,12,2,12,2,114,9,0,0,0, + 0,115,20,0,0,0,2,128,8,3,8,1,22,2,34,1, + 42,1,8,1,46,7,2,128,4,0,115,22,0,0,0,2, + 128,8,3,8,1,22,2,34,1,42,1,2,7,4,1,2, + 249,46,7,6,128,115,176,0,0,0,0,0,1,11,1,11, + 1,11,1,11,1,25,1,25,1,25,1,25,1,6,1,6, + 7,27,1,28,1,28,1,28,1,28,1,28,1,28,1,28, + 1,28,1,6,1,6,7,17,19,22,19,27,19,27,19,27, + 19,27,19,27,1,28,1,28,1,28,1,28,1,28,1,28, + 1,28,1,28,10,39,10,27,10,39,10,39,10,39,10,39, + 10,39,10,41,10,41,10,41,10,41,10,41,10,41,10,41, + 42,50,10,51,10,51,10,51,10,51,10,51,1,7,12,2, + 1,42,1,42,5,8,5,10,5,10,11,41,21,24,11,41, + 11,41,28,34,35,38,28,39,28,39,28,39,28,39,28,39, + 11,41,11,41,5,42,5,42,5,42,5,42,5,42,5,42, + 5,42,5,42,0,0,0,0,0,0,114,9,0,0,0, }; diff --git a/Python/ceval.c b/Python/ceval.c index 351f3b451cd856..3ccb3301157d22 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -6773,17 +6773,24 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, } if (line != -1 && f->f_trace_lines) { /* Trace backward edges (except in 'yield from') or if line number has changed */ + int prev = _PyOpcode_Deopt[_Py_OPCODE(code[instr_prev])]; + int opcode1 = _PyOpcode_Deopt[_Py_OPCODE(*frame->prev_instr)]; + #if 0 - // SEND has no quickened forms, so no need to use _PyOpcode_Deopt here. - int opcode1 = _Py_OPCODE(_PyCode_CODE(frame->f_code)[frame->f_lasti]); - int opcode2 = _Py_OPCODE(_PyCode_CODE(frame->f_code)[instr_prev]); + printf("%s (instr %d, line %d) --> %s (instr %d, line %d)\n", + opname[prev], instr_prev, lastline, + opname[opcode1], _PyInterpreterFrame_LASTI(frame), line); #endif - int trace = line != lastline || + int trace = (opcode1 == FOR_END && prev != JUMP_FORWARD) || + line != lastline || (_PyInterpreterFrame_LASTI(frame) < instr_prev && // SEND has no quickened forms, so no need to use _PyOpcode_Deopt // here: - _Py_OPCODE(*frame->prev_instr) != SEND); + prev != SEND && prev != FOR_END); if (trace) { +#if 0 + printf("calling trace function\n"); +#endif result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } } From 53a87340359c0ba9a4c8294a81d4c06bf131d787 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 01:49:43 -0400 Subject: [PATCH 10/21] when marking backwards jumps, set todo=1 --- Objects/frameobject.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 1dba3533477ee6..a50c01c46152d9 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -268,6 +268,9 @@ mark_stacks(PyCodeObject *code_obj, int len) int64_t target_stack = push_value(next_stack, Object); stacks[i+1] = pop_value(next_stack); j = get_arg(code, i); + if (stacks[j] == UNINITIALIZED && j < i) { + todo = 1; + } assert(j < len); assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack); stacks[j] = target_stack; @@ -570,7 +573,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore } else if (err < 0) { if (start_stack == OVERFLOWED) { - msg = "stack to deep to analyze"; + msg = "stack too deep to analyze"; } else if (start_stack == UNINITIALIZED) { msg = "can't jump from within an exception handler"; From 7d32011a2bc3430eb1b4cc015d8c6cf08e4fcdf0 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 02:38:49 -0400 Subject: [PATCH 11/21] remove debugging code --- Python/ceval.c | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 3ccb3301157d22..dbfb1d08dfbf52 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1375,6 +1375,7 @@ eval_frame_handle_pending(PyThreadState *tstate) /* The stack can grow at most MAXINT deep, as co_nlocals and co_stacksize are ints. */ #define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame))) +#define EMPTY() (STACK_LEVEL() == 0) #define TOP() (stack_pointer[-1]) #define SECOND() (stack_pointer[-2]) #define THIRD() (stack_pointer[-3]) @@ -1386,22 +1387,6 @@ eval_frame_handle_pending(PyThreadState *tstate) #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define BASIC_POP() (*--stack_pointer) -#ifdef Py_DEBUG -#define ASSERT_EMPTY() do { \ - if (STACK_LEVEL()) { \ - fprintf(stderr, "----\n"); \ - while (STACK_LEVEL()) { \ - _PyObject_Dump(BASIC_POP()); \ - fprintf(stderr, "----\n"); \ - } \ - Py_FatalError("Unexpected items on the stack."); \ - } \ -} while (0) -#else -#define ASSERT_EMPTY() ((void)0) -#endif - - #ifdef LLTRACE #define PUSH(v) { (void)(BASIC_PUSH(v), \ lltrace && prtrace(tstate, TOP(), "push")); \ @@ -2381,7 +2366,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int TARGET(RETURN_VALUE) { PyObject *retval = POP(); - ASSERT_EMPTY(); + assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); TRACE_FUNCTION_EXIT(); DTRACE_FUNCTION_EXIT(); @@ -5281,7 +5266,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int if (gen == NULL) { goto error; } - ASSERT_EMPTY(); + assert(EMPTY()); _PyFrame_SetStackPointer(frame, stack_pointer); _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; _PyFrame_Copy(frame, gen_frame); @@ -6775,12 +6760,6 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, /* Trace backward edges (except in 'yield from') or if line number has changed */ int prev = _PyOpcode_Deopt[_Py_OPCODE(code[instr_prev])]; int opcode1 = _PyOpcode_Deopt[_Py_OPCODE(*frame->prev_instr)]; - -#if 0 - printf("%s (instr %d, line %d) --> %s (instr %d, line %d)\n", - opname[prev], instr_prev, lastline, - opname[opcode1], _PyInterpreterFrame_LASTI(frame), line); -#endif int trace = (opcode1 == FOR_END && prev != JUMP_FORWARD) || line != lastline || (_PyInterpreterFrame_LASTI(frame) < instr_prev && @@ -6788,9 +6767,6 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, // here: prev != SEND && prev != FOR_END); if (trace) { -#if 0 - printf("calling trace function\n"); -#endif result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } } From 4a2e781ccf89187ca5d319d3d9807f24201294fb Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 04:18:01 -0400 Subject: [PATCH 12/21] update test_dis --- Lib/test/test_dis.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 2f78d42cc724a6..4067a60cad7113 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -146,12 +146,13 @@ def bug708901(): %3d PRECALL 2 CALL 2 GET_ITER - >> FOR_ITER 2 (to 40) - STORE_FAST 0 (res) + JUMP_FORWARD 2 (to 40) + >> STORE_FAST 0 (res) -%3d JUMP_BACKWARD 3 (to 34) +%3d NOP -%3d >> LOAD_CONST 0 (None) +%3d >> FOR_END 18 (to 36) + LOAD_CONST 0 (None) RETURN_VALUE """ % (bug708901.__code__.co_firstlineno, bug708901.__code__.co_firstlineno + 1, @@ -569,14 +570,14 @@ def foo(x): %3d RESUME 0 BUILD_LIST 0 LOAD_FAST 0 (.0) - >> FOR_ITER 7 (to 24) - STORE_FAST 1 (z) + JUMP_FORWARD 6 (to 22) + >> STORE_FAST 1 (z) LOAD_DEREF 2 (x) LOAD_FAST 1 (z) BINARY_OP 0 (+) LIST_APPEND 2 - JUMP_BACKWARD 8 (to 8) - >> RETURN_VALUE + >> FOR_END 5 (to 10) + RETURN_VALUE """ % (dis_nested_1, __file__, _h.__code__.co_firstlineno + 3, @@ -1217,8 +1218,8 @@ def _prepare_test_cases(): Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=20, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='FOR_ITER', opcode=93, arg=32, argval=98, argrepr='to 98', offset=32, starts_line=None, is_jump_target=True, positions=None), - Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=34, starts_line=None, is_jump_target=False, positions=None), + Instruction(opname='JUMP_FORWARD', opcode=110, arg=31, argval=96, argrepr='to 96', offset=32, starts_line=None, is_jump_target=True, positions=None), + Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=34, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=36, starts_line=4, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=48, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None), @@ -1235,8 +1236,8 @@ def _prepare_test_cases(): Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=48, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='JUMP_BACKWARD', opcode=140, arg=33, argval=32, argrepr='to 32', offset=96, starts_line=7, is_jump_target=True, positions=None), - Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=True, positions=None), + Instruction(opname='FOR_END', opcode=173, arg=17, argval=34, argrepr='to 34', offset=96, starts_line=3, is_jump_target=True, positions=None), + Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=110, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=116, starts_line=None, is_jump_target=False, positions=None), From 0af7e1eefb3fff797e7e57869d3a3c14833d6aac Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 04:44:43 -0400 Subject: [PATCH 13/21] make FOR_END a relative jump --- Include/opcode.h | 2 +- Lib/dis.py | 8 ++++--- Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 2 +- Lib/test/test_dis.py | 6 +++--- Objects/frameobject.c | 2 +- Programs/test_frozenmain.h | 32 ++++++++++++++-------------- Python/ceval.c | 2 +- Python/compile.c | 4 +++- 9 files changed, 32 insertions(+), 28 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index 7c82bfb8ef2209..95090f09736efc 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -198,7 +198,7 @@ static const uint32_t _PyOpcode_RelativeJump[8] = { 0U, 134234112U, 4160U, - 0U, + 8192U, 0U, 0U, }; diff --git a/Lib/dis.py b/Lib/dis.py index d9936ce1a002c3..c251c8f780844c 100644 --- a/Lib/dis.py +++ b/Lib/dis.py @@ -30,7 +30,9 @@ LOAD_CONST = opmap['LOAD_CONST'] LOAD_GLOBAL = opmap['LOAD_GLOBAL'] BINARY_OP = opmap['BINARY_OP'] -JUMP_BACKWARD = opmap['JUMP_BACKWARD'] + +BACK_JUMPS = {code for name, code in opmap.items() + if 'JUMP_BACKWARD' in name} | {opmap['FOR_END']} CACHE = opmap["CACHE"] @@ -442,7 +444,7 @@ def _get_instructions_bytes(code, varname_from_oparg=None, argval = arg*2 argrepr = "to " + repr(argval) elif op in hasjrel: - signed_arg = -arg if op == JUMP_BACKWARD else arg + signed_arg = -arg if op in BACK_JUMPS else arg argval = offset + 2 + signed_arg*2 argrepr = "to " + repr(argval) elif op in haslocal or op in hasfree: @@ -568,7 +570,7 @@ def findlabels(code): for offset, op, arg in _unpack_opargs(code): if arg is not None: if op in hasjrel: - if op == JUMP_BACKWARD: + if op in BACK_JUMPS: arg = -arg label = offset + 2 + arg*2 elif op in hasjabs: diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index cdaa60da4bc72d..0ead992aa699ce 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -414,7 +414,7 @@ def _write_atomic(path, data, mode=0o666): # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # in PC/launcher.c must also be updated. -MAGIC_NUMBER = (3494).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3493).to_bytes(2, 'little') + b'\r\n' _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _PYCACHE = '__pycache__' diff --git a/Lib/opcode.py b/Lib/opcode.py index 32a914d02e5df5..bfc5e18cd5b0e0 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -196,7 +196,7 @@ def jabs_op(name, op, entries=0): def_op('KW_NAMES', 172) hasconst.append(172) -jabs_op('FOR_END', 173) +jrel_op('FOR_END', 173) del def_op, name_op, jrel_op, jabs_op diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 4067a60cad7113..4697ec79e520fc 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -151,7 +151,7 @@ def bug708901(): %3d NOP -%3d >> FOR_END 18 (to 36) +%3d >> FOR_END 3 (to 36) LOAD_CONST 0 (None) RETURN_VALUE """ % (bug708901.__code__.co_firstlineno, @@ -576,7 +576,7 @@ def foo(x): LOAD_FAST 1 (z) BINARY_OP 0 (+) LIST_APPEND 2 - >> FOR_END 5 (to 10) + >> FOR_END 7 (to 10) RETURN_VALUE """ % (dis_nested_1, __file__, @@ -1236,7 +1236,7 @@ def _prepare_test_cases(): Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=48, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='FOR_END', opcode=173, arg=17, argval=34, argrepr='to 34', offset=96, starts_line=3, is_jump_target=True, positions=None), + Instruction(opname='FOR_END', opcode=173, arg=32, argval=34, argrepr='to 34', offset=96, starts_line=3, is_jump_target=True, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=110, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None), diff --git a/Objects/frameobject.c b/Objects/frameobject.c index a50c01c46152d9..4837b9bc137052 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -267,7 +267,7 @@ mark_stacks(PyCodeObject *code_obj, int len) { int64_t target_stack = push_value(next_stack, Object); stacks[i+1] = pop_value(next_stack); - j = get_arg(code, i); + j = i + 1 - get_arg(code, i); if (stacks[j] == UNINITIALIZED && j < i) { todo = 1; } diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h index 23b847159579c0..264aa0aa215b52 100644 --- a/Programs/test_frozenmain.h +++ b/Programs/test_frozenmain.h @@ -12,7 +12,7 @@ unsigned char M_test_frozenmain[] = { 68,0,110,24,90,6,2,0,101,2,100,6,101,6,155,0, 100,7,101,5,101,6,25,0,0,0,0,0,0,0,0,0, 155,0,157,4,166,1,0,0,171,1,0,0,0,0,0,0, - 0,0,1,0,173,61,100,1,83,0,41,8,233,0,0,0, + 0,0,1,0,173,25,100,1,83,0,41,8,233,0,0,0, 0,78,122,18,70,114,111,122,101,110,32,72,101,108,108,111, 32,87,111,114,108,100,122,8,115,121,115,46,97,114,103,118, 218,6,99,111,110,102,105,103,41,5,90,12,112,114,111,103, @@ -28,19 +28,19 @@ unsigned char M_test_frozenmain[] = { 107,101,121,169,0,243,0,0,0,0,250,18,116,101,115,116, 95,102,114,111,122,101,110,109,97,105,110,46,112,121,250,8, 60,109,111,100,117,108,101,62,114,11,0,0,0,1,0,0, - 0,115,20,0,0,0,2,128,8,3,8,1,22,2,34,1, - 42,1,8,1,46,7,2,128,4,0,115,22,0,0,0,2, - 128,8,3,8,1,22,2,34,1,42,1,2,7,4,1,2, - 249,46,7,6,128,115,176,0,0,0,0,0,1,11,1,11, - 1,11,1,11,1,25,1,25,1,25,1,25,1,6,1,6, - 7,27,1,28,1,28,1,28,1,28,1,28,1,28,1,28, - 1,28,1,6,1,6,7,17,19,22,19,27,19,27,19,27, - 19,27,19,27,1,28,1,28,1,28,1,28,1,28,1,28, - 1,28,1,28,10,39,10,27,10,39,10,39,10,39,10,39, - 10,39,10,41,10,41,10,41,10,41,10,41,10,41,10,41, - 42,50,10,51,10,51,10,51,10,51,10,51,1,7,12,2, - 1,42,1,42,5,8,5,10,5,10,11,41,21,24,11,41, - 11,41,28,34,35,38,28,39,28,39,28,39,28,39,28,39, - 11,41,11,41,5,42,5,42,5,42,5,42,5,42,5,42, - 5,42,5,42,0,0,0,0,0,0,114,9,0,0,0, + 0,115,18,0,0,0,2,128,8,3,8,1,22,2,34,1, + 42,1,8,1,46,7,6,249,115,22,0,0,0,2,128,8, + 3,8,1,22,2,34,1,42,1,2,7,4,1,2,249,46, + 7,6,255,115,176,0,0,0,0,0,1,11,1,11,1,11, + 1,11,1,25,1,25,1,25,1,25,1,6,1,6,7,27, + 1,28,1,28,1,28,1,28,1,28,1,28,1,28,1,28, + 1,6,1,6,7,17,19,22,19,27,19,27,19,27,19,27, + 19,27,1,28,1,28,1,28,1,28,1,28,1,28,1,28, + 1,28,10,39,10,27,10,39,10,39,10,39,10,39,10,39, + 10,41,10,41,10,41,10,41,10,41,10,41,10,41,42,50, + 10,51,10,51,10,51,10,51,10,51,1,7,12,2,1,42, + 1,42,5,8,5,10,5,10,11,41,21,24,11,41,11,41, + 28,34,35,38,28,39,28,39,28,39,28,39,28,39,11,41, + 11,41,5,42,5,42,5,42,5,42,5,42,5,42,5,42, + 5,42,12,2,12,2,12,2,114,9,0,0,0, }; diff --git a/Python/ceval.c b/Python/ceval.c index dbfb1d08dfbf52..722d15e1bcc4f3 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4193,7 +4193,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter); if (next != NULL) { PUSH(next); - JUMPTO(oparg); + JUMPBY(-oparg); CHECK_EVAL_BREAKER(); PREDICT(STORE_FAST); PREDICT(UNPACK_SEQUENCE); diff --git a/Python/compile.c b/Python/compile.c index 504cd56302f5b4..9d981f49f01c52 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -7657,12 +7657,14 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c) if (is_relative_jump(instr)) { if (instr->i_oparg < bsize) { assert(instr->i_opcode == JUMP_BACKWARD || - instr->i_opcode == JUMP_BACKWARD_NO_INTERRUPT); + instr->i_opcode == JUMP_BACKWARD_NO_INTERRUPT || + instr->i_opcode == FOR_END); instr->i_oparg = bsize - instr->i_oparg; } else { assert(instr->i_opcode != JUMP_BACKWARD); assert(instr->i_opcode != JUMP_BACKWARD_NO_INTERRUPT); + assert(instr->i_opcode != FOR_END); instr->i_oparg -= bsize; } } From d3552aaccf78a6a70379c948c71a99953f136f03 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 19:15:17 -0400 Subject: [PATCH 14/21] make test.test_bdb and test.test_pdb pass --- Python/ceval.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 722d15e1bcc4f3..c636b2cbfac0ae 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -6763,9 +6763,7 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, int trace = (opcode1 == FOR_END && prev != JUMP_FORWARD) || line != lastline || (_PyInterpreterFrame_LASTI(frame) < instr_prev && - // SEND has no quickened forms, so no need to use _PyOpcode_Deopt - // here: - prev != SEND && prev != FOR_END); + opcode1 != SEND && prev != FOR_END); if (trace) { result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } From 563ca00bbcb3df7ce5b2f688b9da4644d2fc4195 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 21:24:15 -0400 Subject: [PATCH 15/21] refactor maybe_call_line_trace logic --- Python/ceval.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index c636b2cbfac0ae..a8482ebbd961bb 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -6757,14 +6757,20 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, return -1; } if (line != -1 && f->f_trace_lines) { - /* Trace backward edges (except in 'yield from') or if line number has changed */ - int prev = _PyOpcode_Deopt[_Py_OPCODE(code[instr_prev])]; - int opcode1 = _PyOpcode_Deopt[_Py_OPCODE(*frame->prev_instr)]; - int trace = (opcode1 == FOR_END && prev != JUMP_FORWARD) || - line != lastline || - (_PyInterpreterFrame_LASTI(frame) < instr_prev && - opcode1 != SEND && prev != FOR_END); - if (trace) { + int prev_op = _PyOpcode_Deopt[_Py_OPCODE(code[instr_prev])]; + int next_op = _PyOpcode_Deopt[_Py_OPCODE(*frame->prev_instr)]; + // Trace before FOR_END, not after, even though a backwards + // jump happens after. However, don't trace on the first FOR_END + // of the for loop, since we're staying on the same line. + // Also don't trace JUMP_NO_INTERRUPT --> SEND. + bool line_number_changed = (line != lastline); + bool first_iteration = (next_op == FOR_END && + prev_op == JUMP_FORWARD && + !line_number_changed); + bool for_loop_end = (next_op == FOR_END && !first_iteration); + bool back_jump = (_PyInterpreterFrame_LASTI(frame) < instr_prev && + next_op != SEND && prev_op != FOR_END); + if (line_number_changed || for_loop_end || back_jump) { result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None); } } From 719e756d67e4f415472a84a1571322920771f048 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 21:49:41 -0400 Subject: [PATCH 16/21] add blurb --- .../2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst new file mode 100644 index 00000000000000..807c54f0b8a5ad --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst @@ -0,0 +1,5 @@ +Replaced the ``FOR_ITER`` opcode that lived at the top of `for`-loops with a +``FOR_END`` opcode that lives at the bottom. This form of `Loop Inversion +`_ replaces the (unconditional +jump, conditional jump) pair with just one conditional jump during most +iterations. From 862656932278e6f7da57c799f8e56ee589bcb3fa Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 22:03:42 -0400 Subject: [PATCH 17/21] FOR_ITER --> FOR_END in dis.rst --- Doc/library/dis.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index fa0e23a6c96939..861ac22e5d3590 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -981,12 +981,15 @@ iterations of the loop. .. versionadded:: 3.1 -.. opcode:: FOR_ITER (delta) +.. opcode:: FOR_END (delta) TOS is an :term:`iterator`. Call its :meth:`~iterator.__next__` method. If this yields a new value, push it on the stack (leaving the iterator below - it). If the iterator indicates it is exhausted, TOS is popped, and the byte - code counter is incremented by *delta*. + it), then decrement the bytecode counter by *delta*. If the iterator + indicates it is exhausted, then pop TOS and do not decrement the bytecode + counter. + + .. versionadded:: 3.11 .. opcode:: LOAD_GLOBAL (namei) From 2884727afca00638189b0e25470a3e23855c26a5 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 22:06:26 -0400 Subject: [PATCH 18/21] FOR_ITER --> FOR_END in specialize.c --- Python/specialize.c | 60 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Python/specialize.c b/Python/specialize.c index f25e035464ab4d..86fbb3ccd1a29b 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -141,7 +141,7 @@ print_spec_stats(FILE *out, OpcodeStats *stats) { /* Mark some opcodes as specializable for stats, * even though we don't specialize them yet. */ - fprintf(out, "opcode[%d].specializable : 1\n", FOR_ITER); + fprintf(out, "opcode[%d].specializable : 1\n", FOR_END); for (int i = 0; i < 256; i++) { if (_PyOpcode_Adaptive[i]) { fprintf(out, "opcode[%d].specializable : 1\n", i); @@ -454,21 +454,21 @@ initial_counter_value(void) { #define SPEC_FAIL_COMPARE_OP_LONG_FLOAT 23 #define SPEC_FAIL_COMPARE_OP_EXTENDED_ARG 24 -/* FOR_ITER */ -#define SPEC_FAIL_FOR_ITER_GENERATOR 10 -#define SPEC_FAIL_FOR_ITER_COROUTINE 11 -#define SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR 12 -#define SPEC_FAIL_FOR_ITER_LIST 13 -#define SPEC_FAIL_FOR_ITER_TUPLE 14 -#define SPEC_FAIL_FOR_ITER_SET 15 -#define SPEC_FAIL_FOR_ITER_STRING 16 -#define SPEC_FAIL_FOR_ITER_BYTES 17 -#define SPEC_FAIL_FOR_ITER_RANGE 18 -#define SPEC_FAIL_FOR_ITER_ITERTOOLS 19 -#define SPEC_FAIL_FOR_ITER_DICT_KEYS 20 -#define SPEC_FAIL_FOR_ITER_DICT_ITEMS 21 -#define SPEC_FAIL_FOR_ITER_DICT_VALUES 22 -#define SPEC_FAIL_FOR_ITER_ENUMERATE 23 +/* FOR_END */ +#define SPEC_FAIL_FOR_END_GENERATOR 10 +#define SPEC_FAIL_FOR_END_COROUTINE 11 +#define SPEC_FAIL_FOR_END_ASYNC_GENERATOR 12 +#define SPEC_FAIL_FOR_END_LIST 13 +#define SPEC_FAIL_FOR_END_TUPLE 14 +#define SPEC_FAIL_FOR_END_SET 15 +#define SPEC_FAIL_FOR_END_STRING 16 +#define SPEC_FAIL_FOR_END_BYTES 17 +#define SPEC_FAIL_FOR_END_RANGE 18 +#define SPEC_FAIL_FOR_END_ITERTOOLS 19 +#define SPEC_FAIL_FOR_END_DICT_KEYS 20 +#define SPEC_FAIL_FOR_END_DICT_ITEMS 21 +#define SPEC_FAIL_FOR_END_DICT_VALUES 22 +#define SPEC_FAIL_FOR_END_ENUMERATE 23 // UNPACK_SEQUENCE @@ -2004,48 +2004,48 @@ int _PySpecialization_ClassifyIterator(PyObject *iter) { if (PyGen_CheckExact(iter)) { - return SPEC_FAIL_FOR_ITER_GENERATOR; + return SPEC_FAIL_FOR_END_GENERATOR; } if (PyCoro_CheckExact(iter)) { - return SPEC_FAIL_FOR_ITER_COROUTINE; + return SPEC_FAIL_FOR_END_COROUTINE; } if (PyAsyncGen_CheckExact(iter)) { - return SPEC_FAIL_FOR_ITER_ASYNC_GENERATOR; + return SPEC_FAIL_FOR_END_ASYNC_GENERATOR; } PyTypeObject *t = Py_TYPE(iter); if (t == &PyListIter_Type) { - return SPEC_FAIL_FOR_ITER_LIST; + return SPEC_FAIL_FOR_END_LIST; } if (t == &PyTupleIter_Type) { - return SPEC_FAIL_FOR_ITER_TUPLE; + return SPEC_FAIL_FOR_END_TUPLE; } if (t == &PyDictIterKey_Type) { - return SPEC_FAIL_FOR_ITER_DICT_KEYS; + return SPEC_FAIL_FOR_END_DICT_KEYS; } if (t == &PyDictIterValue_Type) { - return SPEC_FAIL_FOR_ITER_DICT_VALUES; + return SPEC_FAIL_FOR_END_DICT_VALUES; } if (t == &PyDictIterItem_Type) { - return SPEC_FAIL_FOR_ITER_DICT_ITEMS; + return SPEC_FAIL_FOR_END_DICT_ITEMS; } if (t == &PySetIter_Type) { - return SPEC_FAIL_FOR_ITER_SET; + return SPEC_FAIL_FOR_END_SET; } if (t == &PyUnicodeIter_Type) { - return SPEC_FAIL_FOR_ITER_STRING; + return SPEC_FAIL_FOR_END_STRING; } if (t == &PyBytesIter_Type) { - return SPEC_FAIL_FOR_ITER_BYTES; + return SPEC_FAIL_FOR_END_BYTES; } if (t == &PyRangeIter_Type) { - return SPEC_FAIL_FOR_ITER_RANGE; + return SPEC_FAIL_FOR_END_RANGE; } if (t == &PyEnum_Type) { - return SPEC_FAIL_FOR_ITER_ENUMERATE; + return SPEC_FAIL_FOR_END_ENUMERATE; } if (strncmp(t->tp_name, "itertools", 8) == 0) { - return SPEC_FAIL_FOR_ITER_ITERTOOLS; + return SPEC_FAIL_FOR_END_ITERTOOLS; } return SPEC_FAIL_OTHER; } From 44baacc01eed95f9b7e834fda1038d6ea8b68c53 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Sun, 10 Apr 2022 22:17:53 -0400 Subject: [PATCH 19/21] Update whatsnew --- Doc/whatsnew/3.11.rst | 6 ++++++ .../2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst index 870330c57969a6..7580d4d71f69cf 100644 --- a/Doc/whatsnew/3.11.rst +++ b/Doc/whatsnew/3.11.rst @@ -763,6 +763,12 @@ CPython bytecode changes * Added :opcode:`JUMP_BACKWARD_NO_INTERRUPT`, which is used in certain loops where it is undesirable to handle interrupts. +* Replaced :opcode:`FOR_ITER` (jumps if iterator exhausted) + with :opcode:`FOR_END` (jumps if iterator is not exhausted). + At the end of each ``for``-loop iteration, instead of an unconditional + jump targeted at a conditional jump, there is now + only one (conditional) jump. + Deprecated ========== diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst b/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst index 807c54f0b8a5ad..c57e4eb22f4342 100644 --- a/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst +++ b/Misc/NEWS.d/next/Core and Builtins/2022-04-10-21-49-23.gh-issue-91432.2yBtR8.rst @@ -1,4 +1,4 @@ -Replaced the ``FOR_ITER`` opcode that lived at the top of `for`-loops with a +Replaced the ``FOR_ITER`` opcode that lived at the top of ``for``-loops with a ``FOR_END`` opcode that lives at the bottom. This form of `Loop Inversion `_ replaces the (unconditional jump, conditional jump) pair with just one conditional jump during most From e4f240e5217eb1143fdb17b46d1e47c3a8afe63a Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Mon, 11 Apr 2022 22:15:23 -0400 Subject: [PATCH 20/21] fix test_dis --- Lib/test/test_dis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 93c519a4e41856..45e8381c35b719 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -1244,7 +1244,7 @@ def _prepare_test_cases(): Instruction(opname='POP_JUMP_FORWARD_IF_FALSE', opcode=114, arg=2, argval=96, argrepr='to 96', offset=90, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=92, starts_line=8, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=16, argval=128, argrepr='to 128', offset=94, starts_line=None, is_jump_target=False, positions=None), - Instruction(opname='FOR_END', opcode=173, arg=32, argval=34, argrepr='to 34', offset=96, starts_line=3, is_jump_target=True, positions=None), + Instruction(opname='FOR_END', opcode=177, arg=32, argval=34, argrepr='to 34', offset=96, starts_line=3, is_jump_target=True, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=3, argval='print', argrepr='NULL + print', offset=98, starts_line=10, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=110, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=112, starts_line=None, is_jump_target=False, positions=None), From 32bed3793edcf91374b4f31867f697380ca3dcd2 Mon Sep 17 00:00:00 2001 From: sweeneyde Date: Mon, 11 Apr 2022 22:28:30 -0400 Subject: [PATCH 21/21] fix opcode.h --- Include/opcode.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/opcode.h b/Include/opcode.h index c022cd2eed7480..f7fb9434ffbe1f 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -491,7 +491,6 @@ static const char *const _PyOpcode_OpName[256] = { [STORE_NAME] = "STORE_NAME", [DELETE_NAME] = "DELETE_NAME", [UNPACK_SEQUENCE] = "UNPACK_SEQUENCE", - [FOR_ITER] = "FOR_ITER", [UNPACK_EX] = "UNPACK_EX", [STORE_ATTR] = "STORE_ATTR", [DELETE_ATTR] = "DELETE_ATTR", @@ -560,6 +559,7 @@ static const char *const _PyOpcode_OpName[256] = { [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", + [FOR_END] = "FOR_END", }; #endif