From f47a953f177868034bae9fe095453b564d2e9f28 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 26 Mar 2021 16:49:24 -0700 Subject: [PATCH 01/47] Replace ROT_* with ROTATE, use list for stores. --- Doc/library/dis.rst | 27 +-- Include/opcode.h | 4 +- Lib/importlib/_bootstrap_external.py | 3 +- Lib/opcode.py | 5 +- Lib/test/test_peepholer.py | 4 +- Python/ceval.c | 41 ++--- Python/compile.c | 92 +++++----- Python/importlib.h | 32 ++-- Python/importlib_external.h | 240 +++++++++++++-------------- Python/importlib_zipimport.h | 6 +- Python/opcode_targets.h | 8 +- 11 files changed, 221 insertions(+), 241 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index c21a667ba17112..11207ab29d5dfe 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -333,25 +333,6 @@ The Python compiler currently generates the following bytecode instructions. Removes the top-of-stack (TOS) item. -.. opcode:: ROT_TWO - - Swaps the two top-most stack items. - - -.. opcode:: ROT_THREE - - Lifts second and third stack item one position up, moves top down to position - three. - - -.. opcode:: ROT_FOUR - - Lifts second, third and fourth stack items one position up, moves top down - to position four. - - .. versionadded:: 3.8 - - .. opcode:: DUP_TOP Duplicates the reference on top of the stack. @@ -1248,6 +1229,14 @@ All of the following opcodes use their arguments. .. versionadded:: 3.10 +.. opcode:: ROTATE (count) + + Lift the top *count* stack items one position up, and move TOS down to + position *count*. + + .. versionadded:: 3.10 + + .. opcode:: HAVE_ARGUMENT This is not really an opcode. It identifies the dividing line between diff --git a/Include/opcode.h b/Include/opcode.h index ea484c5a68fc96..109cc98417897e 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -8,11 +8,8 @@ extern "C" { /* Instruction opcodes for compiled code */ #define POP_TOP 1 -#define ROT_TWO 2 -#define ROT_THREE 3 #define DUP_TOP 4 #define DUP_TOP_TWO 5 -#define ROT_FOUR 6 #define NOP 9 #define UNARY_POSITIVE 10 #define UNARY_NEGATIVE 11 @@ -81,6 +78,7 @@ extern "C" { #define DELETE_ATTR 96 #define STORE_GLOBAL 97 #define DELETE_GLOBAL 98 +#define ROTATE 99 #define LOAD_CONST 100 #define LOAD_NAME 101 #define BUILD_TUPLE 102 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 2dab45d480a113..411c9687015e79 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -314,6 +314,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.10a2 3432 (Function annotation for MAKE_FUNCTION is changed from dict to tuple bpo-42202) # Python 3.10a2 3433 (RERAISE restores f_lasti if oparg != 0) # Python 3.10a6 3434 (PEP 634: Structural Pattern Matching) +# Python 3.10XX 3435 (replace ROT_* with ROTATE) # # MAGIC must change whenever the bytecode emitted by the compiler may no @@ -323,7 +324,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 = (3434).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3435).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 b1197129571cd3..311da7d39d4c15 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -55,11 +55,9 @@ def jabs_op(name, op): # Blank lines correspond to available opcodes def_op('POP_TOP', 1) -def_op('ROT_TWO', 2) -def_op('ROT_THREE', 3) + def_op('DUP_TOP', 4) def_op('DUP_TOP_TWO', 5) -def_op('ROT_FOUR', 6) def_op('NOP', 9) def_op('UNARY_POSITIVE', 10) @@ -139,6 +137,7 @@ def jabs_op(name, op): name_op('DELETE_ATTR', 96) # "" name_op('STORE_GLOBAL', 97) # "" name_op('DELETE_GLOBAL', 98) # "" +def_op('ROTATE', 99) def_op('LOAD_CONST', 100) # Index in const list hasconst.append(100) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 4034154e4dcfb5..61feff360e5c50 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -116,8 +116,8 @@ def f(): def test_pack_unpack(self): for line, elem in ( ('a, = a,', 'LOAD_CONST',), - ('a, b = a, b', 'ROT_TWO',), - ('a, b, c = a, b, c', 'ROT_THREE',), + ('a, b = a, b', 'ROTATE',), + ('a, b, c = a, b, c', 'ROTATE',), ): code = compile(line,'','single') self.assertInBytecode(code, elem) diff --git a/Python/ceval.c b/Python/ceval.c index 3a37017c000d4a..87f76f81049f5b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1894,36 +1894,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) FAST_DISPATCH(); } - case TARGET(ROT_TWO): { - PyObject *top = TOP(); - PyObject *second = SECOND(); - SET_TOP(second); - SET_SECOND(top); - FAST_DISPATCH(); - } - - case TARGET(ROT_THREE): { - PyObject *top = TOP(); - PyObject *second = SECOND(); - PyObject *third = THIRD(); - SET_TOP(second); - SET_SECOND(third); - SET_THIRD(top); - FAST_DISPATCH(); - } - - case TARGET(ROT_FOUR): { - PyObject *top = TOP(); - PyObject *second = SECOND(); - PyObject *third = THIRD(); - PyObject *fourth = FOURTH(); - SET_TOP(second); - SET_SECOND(third); - SET_THIRD(fourth); - SET_FOURTH(top); - FAST_DISPATCH(); - } - case TARGET(DUP_TOP): { PyObject *top = TOP(); Py_INCREF(top); @@ -4452,6 +4422,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) DISPATCH(); } + case TARGET(ROTATE): { + PyObject *top = TOP(); + memmove(&PEEK(oparg - 1), &PEEK(oparg), + sizeof(PyObject*) * (oparg - 1)); + // for (int i = 1; i < oparg; i++) { + // PEEK(i) = PEEK(i + 1); + // } + PEEK(oparg) = top; + FAST_DISPATCH(); + } + case TARGET(EXTENDED_ARG): { int oldoparg = oparg; NEXTOPARG(); diff --git a/Python/compile.c b/Python/compile.c index bed2a1c944d962..d5f52ad1a97e63 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -908,10 +908,6 @@ stack_effect(int opcode, int oparg, int jump) /* Stack manipulation */ case POP_TOP: return -1; - case ROT_TWO: - case ROT_THREE: - case ROT_FOUR: - return 0; case DUP_TOP: return 1; case DUP_TOP_TWO: @@ -1155,6 +1151,8 @@ stack_effect(int opcode, int oparg, int jump) return 1; case MATCH_KEYS: return 2; + case ROTATE: + return 0; default: return PY_INVALID_STACK_EFFECT; } @@ -1703,7 +1701,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case FOR_LOOP: /* Pop the iterator */ if (preserve_tos) { - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); } ADDOP(c, POP_TOP); return 1; @@ -1733,13 +1731,13 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case FINALLY_END: if (preserve_tos) { - ADDOP(c, ROT_FOUR); + ADDOP_I(c, ROTATE, 4); } ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); if (preserve_tos) { - ADDOP(c, ROT_FOUR); + ADDOP_I(c, ROTATE, 4); } ADDOP(c, POP_EXCEPT); return 1; @@ -1748,7 +1746,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case ASYNC_WITH: ADDOP(c, POP_BLOCK); if (preserve_tos) { - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); } if(!compiler_call_exit_with_nones(c)) { return 0; @@ -1766,7 +1764,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, ADDOP(c, POP_BLOCK); } if (preserve_tos) { - ADDOP(c, ROT_FOUR); + ADDOP_I(c, ROTATE, 4); } ADDOP(c, POP_EXCEPT); if (info->fb_datum) { @@ -1778,7 +1776,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case POP_VALUE: if (preserve_tos) { - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); } ADDOP(c, POP_TOP); return 1; @@ -2609,7 +2607,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP(c, DUP_TOP); - ADDOP(c, ROT_THREE); + ADDOP_I(c, ROTATE, 3); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, cleanup); NEXT_BLOCK(c); @@ -3213,7 +3211,7 @@ compiler_import_as(struct compiler *c, identifier name, identifier asname) if (dot == -1) { break; } - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); ADDOP(c, POP_TOP); } if (!compiler_nameop(c, asname, Store)) { @@ -3979,7 +3977,7 @@ compiler_compare(struct compiler *c, expr_ty e) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP(c, DUP_TOP); - ADDOP(c, ROT_THREE); + ADDOP_I(c, ROTATE, 3); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, cleanup); NEXT_BLOCK(c); @@ -3991,7 +3989,7 @@ compiler_compare(struct compiler *c, expr_ty e) return 0; ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); compiler_use_next_block(c, cleanup); - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); ADDOP(c, POP_TOP); compiler_use_next_block(c, end); } @@ -5218,11 +5216,11 @@ compiler_augassign(struct compiler *c, stmt_ty s) switch (e->kind) { case Attribute_kind: c->u->u_lineno = e->end_lineno; - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); break; case Subscript_kind: - ADDOP(c, ROT_THREE); + ADDOP_I(c, ROTATE, 3); ADDOP(c, STORE_SUBSCR); break; case Name_kind: @@ -5488,10 +5486,10 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) assert(!_PyUnicode_EqualToASCIIString(n, "_")); // Can't assign to the same name twice: if (pc->stores == NULL) { - RETURN_IF_FALSE(pc->stores = PySet_New(NULL)); + RETURN_IF_FALSE(pc->stores = PyList_New(0)); } else { - int duplicate = PySet_Contains(pc->stores, n); + int duplicate = PySequence_Contains(pc->stores, n); if (duplicate < 0) { return 0; } @@ -5500,7 +5498,7 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) return compiler_error(c, e, n); } } - RETURN_IF_FALSE(!PySet_Add(pc->stores, n)); + RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); RETURN_IF_FALSE(compiler_nameop(c, n, Store)); return 1; } @@ -5851,8 +5849,9 @@ static int compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) { assert(p->kind == MatchOr_kind); - // control is the set of names bound by the first alternative. If all of the - // others bind the same names (they should), then this becomes pc->stores. + // control is the list of names bound by the first alternative. If all of + // the others bind the same names (they should), then this becomes + // pc->stores. PyObject *control = NULL; basicblock *end, *pass_pop_1; RETURN_IF_FALSE(end = compiler_new_block(c)); @@ -5860,12 +5859,13 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns); assert(size > 1); // We're going to be messing with pc. Keep the original info handy: - PyObject *stores_init = pc->stores; + PyObject *stores_init; + RETURN_IF_FALSE(stores_init = pc->stores ? pc->stores : PyList_New(0)); int allow_irrefutable = pc->allow_irrefutable; for (Py_ssize_t i = 0; i < size; i++) { - // NOTE: Can't use our nice returning macros in here: they'll leak sets! + // NOTE: Can't use our nice returning macros here: they'll leak lists! expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); - pc->stores = PySet_New(stores_init); + pc->stores = PySequence_List(stores_init); // An irrefutable sub-pattern must be last, if it is allowed at all: int is_last = i == size - 1; pc->allow_irrefutable = allow_irrefutable && is_last; @@ -5886,19 +5886,26 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) control = pc->stores; continue; } - if (PySet_GET_SIZE(pc->stores) || PySet_GET_SIZE(control)) { - // Otherwise, check to see if we differ from the control set: - PyObject *diff = PyNumber_InPlaceXor(pc->stores, control); - if (diff == NULL) { - goto fail; - } - if (PySet_GET_SIZE(diff)) { - // The names differ! Raise. - Py_DECREF(diff); - compiler_error(c, "alternative patterns bind different names"); - goto fail; + if (PyList_GET_SIZE(pc->stores) != PyList_GET_SIZE(control)) { + goto diff; + } + if (PyList_GET_SIZE(stores_init) < PyList_GET_SIZE(pc->stores)) + { + // Otherwise, check to see if we differ from the control list: + Py_ssize_t j, k; + for (j = PyList_GET_SIZE(stores_init); j < PyList_GET_SIZE(control); + j++) + { + k = PySequence_Index(pc->stores, PyList_GET_ITEM(control, j)); + if (k < 0) { + PyErr_Clear(); + goto diff; + } + assert(j <= k); + while (k++ < PyList_GET_SIZE(control)) { + // ADDOP_I(c, ROTATE, PyList_GET_SIZE(control) - j) + } } - Py_DECREF(diff); } Py_DECREF(pc->stores); } @@ -5912,6 +5919,8 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST(c, Py_True); compiler_use_next_block(c, end); return 1; +diff: + compiler_error(c, "alternative patterns bind different names"); fail: Py_XDECREF(stores_init); Py_XDECREF(control); @@ -6062,7 +6071,7 @@ compiler_match(struct compiler *c, stmt_ty s) // We use pc.stores to track: // - Repeated name assignments in the same pattern. // - Different name assignments in alternatives. - // It's a set of names, but we don't create it until it's needed: + // It's a list of names, but we don't create it until it's needed: pc.stores = NULL; match_case_ty m = asdl_seq_GET(s->v.Match.cases, cases - 1); int has_default = WILDCARD_CHECK(m->pattern) && 1 < cases; @@ -6899,12 +6908,15 @@ optimize_basic_block(basicblock *bb, PyObject *consts) bb->b_instr[i+1].i_opcode = NOP; break; case 2: - inst->i_opcode = ROT_TWO; + inst->i_opcode = ROTATE; + inst->i_oparg = 2; bb->b_instr[i+1].i_opcode = NOP; break; case 3: - inst->i_opcode = ROT_THREE; - bb->b_instr[i+1].i_opcode = ROT_TWO; + inst->i_opcode = ROTATE; + inst->i_oparg = 3; + bb->b_instr[i+1].i_opcode = ROTATE; + bb->b_instr[i+1].i_oparg = 2; } break; } diff --git a/Python/importlib.h b/Python/importlib.h index 633c642a1401ff..f606ce84f44a3f 100644 --- a/Python/importlib.h +++ b/Python/importlib.h @@ -56,7 +56,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8, 0,0,0,67,0,0,0,115,38,0,0,0,122,8,124,0, 106,0,87,0,83,0,4,0,116,1,121,36,1,0,1,0, - 1,0,116,2,124,0,131,1,106,0,6,0,89,0,83,0, + 1,0,116,2,124,0,131,1,106,0,99,4,89,0,83,0, 119,0,169,1,78,41,3,218,12,95,95,113,117,97,108,110, 97,109,101,95,95,218,14,65,116,116,114,105,98,117,116,101, 69,114,114,111,114,218,4,116,121,112,101,41,1,218,3,111, @@ -154,11 +154,11 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 60,0,122,172,9,0,124,0,106,3,143,126,1,0,124,0, 106,4,100,2,107,2,115,48,124,0,106,5,124,1,107,2, 114,92,124,1,124,0,95,5,124,0,4,0,106,4,100,3, - 55,0,2,0,95,4,87,0,100,4,4,0,4,0,131,3, + 55,0,99,2,95,4,87,0,100,4,4,0,4,0,131,3, 1,0,87,0,116,2,124,1,61,0,100,1,83,0,124,0, 160,6,161,0,114,112,116,7,100,5,124,0,22,0,131,1, 130,1,124,0,106,8,160,9,100,6,161,1,114,138,124,0, - 4,0,106,10,100,3,55,0,2,0,95,10,87,0,100,4, + 4,0,106,10,100,3,55,0,99,2,95,10,87,0,100,4, 4,0,4,0,131,3,1,0,110,16,49,0,115,158,119,1, 1,0,1,0,1,0,89,0,1,0,124,0,106,8,160,9, 161,0,1,0,124,0,106,8,160,11,161,0,1,0,113,20, @@ -192,10 +192,10 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 115,144,0,0,0,116,0,160,1,161,0,125,1,124,0,106, 2,143,110,1,0,124,0,106,3,124,1,107,3,114,34,116, 4,100,1,131,1,130,1,124,0,106,5,100,2,107,4,115, - 48,74,0,130,1,124,0,4,0,106,5,100,3,56,0,2, - 0,95,5,124,0,106,5,100,2,107,2,114,108,100,0,124, + 48,74,0,130,1,124,0,4,0,106,5,100,3,56,0,99, + 2,95,5,124,0,106,5,100,2,107,2,114,108,100,0,124, 0,95,3,124,0,106,6,114,108,124,0,4,0,106,6,100, - 3,56,0,2,0,95,6,124,0,106,7,160,8,161,0,1, + 3,56,0,99,2,95,6,124,0,106,7,160,8,161,0,1, 0,87,0,100,0,4,0,4,0,131,3,1,0,100,0,83, 0,49,0,115,130,119,1,1,0,1,0,1,0,89,0,1, 0,100,0,83,0,41,4,78,250,31,99,97,110,110,111,116, @@ -248,7 +248,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 100,117,108,101,76,111,99,107,46,95,95,105,110,105,116,95, 95,99,1,0,0,0,0,0,0,0,0,0,0,0,1,0, 0,0,3,0,0,0,67,0,0,0,115,18,0,0,0,124, - 0,4,0,106,0,100,1,55,0,2,0,95,0,100,2,83, + 0,4,0,106,0,100,1,55,0,99,2,95,0,100,2,83, 0,41,3,78,114,42,0,0,0,84,41,1,114,30,0,0, 0,114,52,0,0,0,114,5,0,0,0,114,5,0,0,0, 114,6,0,0,0,114,43,0,0,0,150,0,0,0,115,6, @@ -257,7 +257,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 105,114,101,99,1,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,0,3,0,0,0,67,0,0,0,115,36,0,0, 0,124,0,106,0,100,1,107,2,114,18,116,1,100,2,131, - 1,130,1,124,0,4,0,106,0,100,3,56,0,2,0,95, + 1,130,1,124,0,4,0,106,0,100,3,56,0,99,2,95, 0,100,0,83,0,41,4,78,114,25,0,0,0,114,46,0, 0,0,114,42,0,0,0,41,2,114,30,0,0,0,114,47, 0,0,0,114,52,0,0,0,114,5,0,0,0,114,5,0, @@ -529,8 +529,8 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 1,0,1,0,1,0,100,5,125,3,89,0,122,10,124,0, 106,7,125,4,87,0,110,50,4,0,116,6,121,178,1,0, 1,0,1,0,124,1,100,2,117,0,114,150,100,6,160,8, - 124,3,161,1,6,0,89,0,83,0,100,7,160,8,124,3, - 124,1,161,2,6,0,89,0,83,0,100,8,160,8,124,3, + 124,3,161,1,99,4,89,0,83,0,100,7,160,8,124,3, + 124,1,161,2,99,4,89,0,83,0,100,8,160,8,124,3, 124,4,161,2,83,0,119,0,119,0,119,0,41,9,122,44, 84,104,101,32,105,109,112,108,101,109,101,110,116,97,116,105, 111,110,32,111,102,32,77,111,100,117,108,101,84,121,112,101, @@ -705,7 +705,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 107,2,111,76,124,2,124,1,106,0,107,2,111,76,124,0, 106,4,124,1,106,4,107,2,111,76,124,0,106,5,124,1, 106,5,107,2,87,0,83,0,4,0,116,6,121,100,1,0, - 1,0,1,0,116,7,6,0,89,0,83,0,119,0,114,0, + 1,0,1,0,116,7,99,4,89,0,83,0,119,0,114,0, 0,0,0,41,8,114,129,0,0,0,114,20,0,0,0,114, 122,0,0,0,114,126,0,0,0,218,6,99,97,99,104,101, 100,218,12,104,97,115,95,108,111,99,97,116,105,111,110,114, @@ -1051,7 +1051,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,0,99,1,0,0,0,0,0,0,0,0,0,0,0,1, 0,0,0,8,0,0,0,67,0,0,0,115,54,0,0,0, 116,0,124,0,106,1,131,1,143,24,1,0,116,2,124,0, - 131,1,87,0,2,0,100,1,4,0,4,0,131,3,1,0, + 131,1,87,0,99,2,100,1,4,0,4,0,131,3,1,0, 83,0,49,0,115,40,119,1,1,0,1,0,1,0,89,0, 1,0,100,1,83,0,41,2,122,191,82,101,116,117,114,110, 32,97,32,110,101,119,32,109,111,100,117,108,101,32,111,98, @@ -1432,9 +1432,9 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 116,0,106,6,118,0,144,1,114,18,116,0,106,6,124,0, 25,0,125,8,122,10,124,8,106,11,125,9,87,0,110,26, 4,0,116,9,144,1,121,32,1,0,1,0,1,0,124,7, - 6,0,89,0,2,0,1,0,83,0,124,9,100,1,117,0, - 144,1,114,10,124,7,2,0,1,0,83,0,124,9,2,0, - 1,0,83,0,124,7,2,0,1,0,83,0,113,52,100,1, + 99,4,89,0,99,2,1,0,83,0,124,9,100,1,117,0, + 144,1,114,10,124,7,99,2,1,0,83,0,124,9,99,2, + 1,0,83,0,124,7,99,2,1,0,83,0,113,52,100,1, 83,0,119,0,119,0,41,4,122,21,70,105,110,100,32,97, 32,109,111,100,117,108,101,39,115,32,115,112,101,99,46,78, 122,53,115,121,115,46,109,101,116,97,95,112,97,116,104,32, @@ -1535,7 +1535,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 67,0,0,0,115,128,0,0,0,116,0,124,0,131,1,143, 62,1,0,116,1,106,2,160,3,124,0,116,4,161,2,125, 2,124,2,116,4,117,0,114,56,116,5,124,0,124,1,131, - 2,87,0,2,0,100,1,4,0,4,0,131,3,1,0,83, + 2,87,0,99,2,100,1,4,0,4,0,131,3,1,0,83, 0,87,0,100,1,4,0,4,0,131,3,1,0,110,16,49, 0,115,76,119,1,1,0,1,0,1,0,89,0,1,0,124, 2,100,1,117,0,114,116,100,2,160,6,124,0,161,1,125, diff --git a/Python/importlib_external.h b/Python/importlib_external.h index f9045892885f2b..ba5a642168ec27 100644 --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -196,7 +196,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 124,3,102,2,83,0,116,4,124,0,131,1,68,0,93,42, 125,4,124,4,116,1,118,0,114,86,124,0,106,5,124,4, 100,1,100,2,141,2,92,2,125,1,125,3,124,1,124,3, - 102,2,2,0,1,0,83,0,113,44,100,3,124,0,102,2, + 102,2,99,2,1,0,83,0,113,44,100,3,124,0,102,2, 83,0,41,5,122,32,82,101,112,108,97,99,101,109,101,110, 116,32,102,111,114,32,111,115,46,112,97,116,104,46,115,112, 108,105,116,40,41,46,114,3,0,0,0,41,1,90,8,109, @@ -315,7 +315,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,115,38,0,0,0,16,5,6,1,22,1,4,255, 2,2,14,3,24,1,16,128,18,1,12,1,2,1,12,1, 2,3,12,254,2,1,2,1,2,254,2,253,255,128,114,84, - 0,0,0,105,106,13,0,0,114,45,0,0,0,114,33,0, + 0,0,0,105,107,13,0,0,114,45,0,0,0,114,33,0, 0,0,115,2,0,0,0,13,10,90,11,95,95,112,121,99, 97,99,104,101,95,95,122,4,111,112,116,45,122,3,46,112, 121,122,4,46,112,121,119,122,4,46,112,121,99,41,1,218, @@ -429,7 +429,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 90,15,97,108,109,111,115,116,95,102,105,108,101,110,97,109, 101,218,8,102,105,108,101,110,97,109,101,114,7,0,0,0, 114,7,0,0,0,114,8,0,0,0,218,17,99,97,99,104, - 101,95,102,114,111,109,95,115,111,117,114,99,101,86,1,0, + 101,95,102,114,111,109,95,115,111,117,114,99,101,87,1,0, 0,115,74,0,0,0,8,18,6,1,2,1,4,255,8,2, 4,1,8,1,12,1,10,1,12,1,16,1,8,1,8,1, 8,1,24,1,8,1,12,1,6,1,8,2,8,1,8,1, @@ -510,7 +510,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,90,9,111,112,116,95,108,101,118,101,108,90,13,98, 97,115,101,95,102,105,108,101,110,97,109,101,114,7,0,0, 0,114,7,0,0,0,114,8,0,0,0,218,17,115,111,117, - 114,99,101,95,102,114,111,109,95,99,97,99,104,101,157,1, + 114,99,101,95,102,114,111,109,95,99,97,99,104,101,158,1, 0,0,115,62,0,0,0,12,9,8,1,10,1,12,1,4, 1,10,1,12,1,14,1,16,1,4,1,4,1,12,1,8, 1,8,1,2,1,8,255,10,2,8,1,14,1,10,1,16, @@ -546,7 +546,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 120,116,101,110,115,105,111,110,218,11,115,111,117,114,99,101, 95,112,97,116,104,114,7,0,0,0,114,7,0,0,0,114, 8,0,0,0,218,15,95,103,101,116,95,115,111,117,114,99, - 101,102,105,108,101,197,1,0,0,115,24,0,0,0,12,7, + 101,102,105,108,101,198,1,0,0,115,24,0,0,0,12,7, 4,1,16,1,24,1,4,1,2,1,12,1,16,1,14,1, 16,1,2,254,255,128,114,120,0,0,0,99,1,0,0,0, 0,0,0,0,0,0,0,0,1,0,0,0,8,0,0,0, @@ -559,7 +559,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 112,108,101,114,113,0,0,0,114,109,0,0,0,114,95,0, 0,0,114,101,0,0,0,41,1,114,108,0,0,0,114,7, 0,0,0,114,7,0,0,0,114,8,0,0,0,218,11,95, - 103,101,116,95,99,97,99,104,101,100,216,1,0,0,115,20, + 103,101,116,95,99,97,99,104,101,100,217,1,0,0,115,20, 0,0,0,14,1,2,1,10,1,12,1,6,1,14,1,4, 1,4,2,2,251,255,128,114,124,0,0,0,99,1,0,0, 0,0,0,0,0,0,0,0,0,2,0,0,0,8,0,0, @@ -574,7 +574,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,114,65,0,0,0,114,64,0,0,0,41,2,114, 58,0,0,0,114,66,0,0,0,114,7,0,0,0,114,7, 0,0,0,114,8,0,0,0,218,10,95,99,97,108,99,95, - 109,111,100,101,228,1,0,0,115,16,0,0,0,2,2,14, + 109,111,100,101,229,1,0,0,115,16,0,0,0,2,2,14, 1,12,1,6,1,8,3,4,1,2,251,255,128,114,126,0, 0,0,99,1,0,0,0,0,0,0,0,0,0,0,0,3, 0,0,0,4,0,0,0,3,0,0,0,115,52,0,0,0, @@ -611,7 +611,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 108,102,114,128,0,0,0,218,4,97,114,103,115,218,6,107, 119,97,114,103,115,169,1,218,6,109,101,116,104,111,100,114, 7,0,0,0,114,8,0,0,0,218,19,95,99,104,101,99, - 107,95,110,97,109,101,95,119,114,97,112,112,101,114,248,1, + 107,95,110,97,109,101,95,119,114,97,112,112,101,114,249,1, 0,0,115,20,0,0,0,8,1,8,1,10,1,4,1,8, 1,2,255,2,1,6,255,24,2,255,128,122,40,95,99,104, 101,99,107,95,110,97,109,101,46,60,108,111,99,97,108,115, @@ -630,14 +630,14 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 99,116,95,95,218,6,117,112,100,97,116,101,41,3,90,3, 110,101,119,90,3,111,108,100,114,82,0,0,0,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,218,5,95,119, - 114,97,112,5,2,0,0,115,12,0,0,0,8,1,10,1, + 114,97,112,6,2,0,0,115,12,0,0,0,8,1,10,1, 18,1,2,128,18,1,255,128,122,26,95,99,104,101,99,107, 95,110,97,109,101,46,60,108,111,99,97,108,115,62,46,95, 119,114,97,112,41,1,78,41,2,218,10,95,98,111,111,116, 115,116,114,97,112,114,145,0,0,0,41,3,114,134,0,0, 0,114,135,0,0,0,114,145,0,0,0,114,7,0,0,0, 114,133,0,0,0,114,8,0,0,0,218,11,95,99,104,101, - 99,107,95,110,97,109,101,240,1,0,0,115,14,0,0,0, + 99,107,95,110,97,109,101,241,1,0,0,115,14,0,0,0, 14,8,8,10,8,1,8,2,10,6,4,1,255,128,114,147, 0,0,0,99,2,0,0,0,0,0,0,0,0,0,0,0, 5,0,0,0,6,0,0,0,67,0,0,0,115,60,0,0, @@ -665,7 +665,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 97,109,101,218,6,108,111,97,100,101,114,218,8,112,111,114, 116,105,111,110,115,218,3,109,115,103,114,7,0,0,0,114, 7,0,0,0,114,8,0,0,0,218,17,95,102,105,110,100, - 95,109,111,100,117,108,101,95,115,104,105,109,15,2,0,0, + 95,109,111,100,117,108,101,95,115,104,105,109,16,2,0,0, 115,12,0,0,0,14,10,16,1,4,1,22,1,4,1,255, 128,114,154,0,0,0,99,3,0,0,0,0,0,0,0,0, 0,0,0,6,0,0,0,4,0,0,0,67,0,0,0,115, @@ -733,7 +733,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 115,90,5,109,97,103,105,99,114,105,0,0,0,114,17,0, 0,0,114,7,0,0,0,114,7,0,0,0,114,8,0,0, 0,218,13,95,99,108,97,115,115,105,102,121,95,112,121,99, - 32,2,0,0,115,30,0,0,0,12,16,8,1,16,1,12, + 33,2,0,0,115,30,0,0,0,12,16,8,1,16,1,12, 1,16,1,12,1,10,1,12,1,8,1,16,1,8,2,16, 1,16,1,4,1,255,128,114,163,0,0,0,99,5,0,0, 0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0, @@ -788,7 +788,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,114,162,0,0,0,114,105,0,0,0,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,218,23,95,118, 97,108,105,100,97,116,101,95,116,105,109,101,115,116,97,109, - 112,95,112,121,99,65,2,0,0,115,20,0,0,0,24,19, + 112,95,112,121,99,66,2,0,0,115,20,0,0,0,24,19, 10,1,12,1,16,1,8,1,22,1,2,255,22,2,8,254, 255,128,114,167,0,0,0,99,4,0,0,0,0,0,0,0, 0,0,0,0,4,0,0,0,4,0,0,0,67,0,0,0, @@ -834,7 +834,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,218,11,115,111,117,114,99,101,95,104,97,115,104,114, 128,0,0,0,114,162,0,0,0,114,7,0,0,0,114,7, 0,0,0,114,8,0,0,0,218,18,95,118,97,108,105,100, - 97,116,101,95,104,97,115,104,95,112,121,99,93,2,0,0, + 97,116,101,95,104,97,115,104,95,112,121,99,94,2,0,0, 115,16,0,0,0,16,17,2,1,8,1,4,255,2,2,6, 254,4,255,255,128,114,169,0,0,0,99,4,0,0,0,0, 0,0,0,0,0,0,0,5,0,0,0,5,0,0,0,67, @@ -858,7 +858,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 114,42,0,0,0,114,128,0,0,0,114,118,0,0,0,114, 119,0,0,0,218,4,99,111,100,101,114,7,0,0,0,114, 7,0,0,0,114,8,0,0,0,218,17,95,99,111,109,112, - 105,108,101,95,98,121,116,101,99,111,100,101,117,2,0,0, + 105,108,101,95,98,121,116,101,99,111,100,101,118,2,0,0, 115,20,0,0,0,10,2,10,1,12,1,8,1,12,1,4, 1,10,2,4,1,6,255,255,128,114,176,0,0,0,99,3, 0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5, @@ -877,7 +877,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 114,166,0,0,0,114,42,0,0,0,114,7,0,0,0,114, 7,0,0,0,114,8,0,0,0,218,22,95,99,111,100,101, 95,116,111,95,116,105,109,101,115,116,97,109,112,95,112,121, - 99,130,2,0,0,115,14,0,0,0,8,2,14,1,14,1, + 99,131,2,0,0,115,14,0,0,0,8,2,14,1,14,1, 14,1,16,1,4,1,255,128,114,181,0,0,0,84,99,3, 0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5, 0,0,0,67,0,0,0,115,80,0,0,0,116,0,116,1, @@ -895,7 +895,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,90,7,99,104,101,99,107,101,100,114,42,0,0,0, 114,17,0,0,0,114,7,0,0,0,114,7,0,0,0,114, 8,0,0,0,218,17,95,99,111,100,101,95,116,111,95,104, - 97,115,104,95,112,121,99,140,2,0,0,115,16,0,0,0, + 97,115,104,95,112,121,99,141,2,0,0,115,16,0,0,0, 8,2,12,1,14,1,16,1,10,1,16,1,4,1,255,128, 114,182,0,0,0,99,1,0,0,0,0,0,0,0,0,0, 0,0,5,0,0,0,6,0,0,0,67,0,0,0,115,62, @@ -923,7 +923,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 105,110,103,90,15,110,101,119,108,105,110,101,95,100,101,99, 111,100,101,114,114,7,0,0,0,114,7,0,0,0,114,8, 0,0,0,218,13,100,101,99,111,100,101,95,115,111,117,114, - 99,101,151,2,0,0,115,12,0,0,0,8,5,12,1,10, + 99,101,152,2,0,0,115,12,0,0,0,8,5,12,1,10, 1,12,1,20,1,255,128,114,187,0,0,0,169,2,114,151, 0,0,0,218,26,115,117,98,109,111,100,117,108,101,95,115, 101,97,114,99,104,95,108,111,99,97,116,105,111,110,115,99, @@ -984,7 +984,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 8,115,117,102,102,105,120,101,115,114,193,0,0,0,90,7, 100,105,114,110,97,109,101,114,7,0,0,0,114,7,0,0, 0,114,8,0,0,0,218,23,115,112,101,99,95,102,114,111, - 109,95,102,105,108,101,95,108,111,99,97,116,105,111,110,168, + 109,95,102,105,108,101,95,108,111,99,97,116,105,111,110,169, 2,0,0,115,74,0,0,0,8,12,4,4,10,1,2,2, 14,1,14,1,4,1,2,251,10,7,16,8,6,1,8,3, 14,1,14,1,10,1,6,1,4,1,2,253,4,5,8,3, @@ -1016,14 +1016,14 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,67,0,0,0,115,50,0,0,0,122,16,116,0, 160,1,116,0,106,2,124,0,161,2,87,0,83,0,4,0, 116,3,121,48,1,0,1,0,1,0,116,0,160,1,116,0, - 106,4,124,0,161,2,6,0,89,0,83,0,119,0,114,121, + 106,4,124,0,161,2,99,4,89,0,83,0,119,0,114,121, 0,0,0,41,5,218,6,119,105,110,114,101,103,90,7,79, 112,101,110,75,101,121,90,17,72,75,69,89,95,67,85,82, 82,69,78,84,95,85,83,69,82,114,64,0,0,0,90,18, 72,75,69,89,95,76,79,67,65,76,95,77,65,67,72,73, 78,69,114,20,0,0,0,114,7,0,0,0,114,7,0,0, 0,114,8,0,0,0,218,14,95,111,112,101,110,95,114,101, - 103,105,115,116,114,121,248,2,0,0,115,12,0,0,0,2, + 103,105,115,116,114,121,249,2,0,0,115,12,0,0,0,2, 2,16,1,12,1,18,1,2,255,255,128,122,36,87,105,110, 100,111,119,115,82,101,103,105,115,116,114,121,70,105,110,100, 101,114,46,95,111,112,101,110,95,114,101,103,105,115,116,114, @@ -1050,7 +1050,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 116,114,121,95,107,101,121,114,21,0,0,0,90,4,104,107, 101,121,218,8,102,105,108,101,112,97,116,104,114,7,0,0, 0,114,7,0,0,0,114,8,0,0,0,218,16,95,115,101, - 97,114,99,104,95,114,101,103,105,115,116,114,121,255,2,0, + 97,114,99,104,95,114,101,103,105,115,116,114,121,0,3,0, 0,115,30,0,0,0,6,2,8,1,6,2,6,1,16,1, 6,255,2,2,12,1,26,1,18,128,4,3,12,254,6,1, 2,255,255,128,122,38,87,105,110,100,111,119,115,82,101,103, @@ -1064,7 +1064,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,116,3,131,0,68,0,93,52,92,2,125,5,125,6,124, 4,160,4,116,5,124,6,131,1,161,1,114,112,116,6,106, 7,124,1,124,5,124,1,124,4,131,2,124,4,100,1,141, - 3,125,7,124,7,2,0,1,0,83,0,113,60,100,0,83, + 3,125,7,124,7,99,2,1,0,83,0,113,60,100,0,83, 0,119,0,41,2,78,114,191,0,0,0,41,8,114,211,0, 0,0,114,63,0,0,0,114,64,0,0,0,114,195,0,0, 0,114,122,0,0,0,114,123,0,0,0,114,146,0,0,0, @@ -1073,7 +1073,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,218,6,116,97,114,103,101,116,114,210,0,0,0, 114,151,0,0,0,114,200,0,0,0,114,198,0,0,0,114, 7,0,0,0,114,7,0,0,0,114,8,0,0,0,218,9, - 102,105,110,100,95,115,112,101,99,14,3,0,0,115,36,0, + 102,105,110,100,95,115,112,101,99,15,3,0,0,115,36,0, 0,0,10,2,8,1,4,1,2,1,12,1,12,1,6,1, 14,1,14,1,6,1,8,1,2,1,6,254,8,3,2,252, 4,255,2,254,255,128,122,31,87,105,110,100,111,119,115,82, @@ -1093,7 +1093,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 169,4,114,209,0,0,0,114,150,0,0,0,114,58,0,0, 0,114,198,0,0,0,114,7,0,0,0,114,7,0,0,0, 114,8,0,0,0,218,11,102,105,110,100,95,109,111,100,117, - 108,101,30,3,0,0,115,10,0,0,0,12,7,8,1,6, + 108,101,31,3,0,0,115,10,0,0,0,12,7,8,1,6, 1,4,2,255,128,122,33,87,105,110,100,111,119,115,82,101, 103,105,115,116,114,121,70,105,110,100,101,114,46,102,105,110, 100,95,109,111,100,117,108,101,41,2,78,78,41,1,78,41, @@ -1105,7 +1105,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 104,111,100,114,204,0,0,0,218,11,99,108,97,115,115,109, 101,116,104,111,100,114,211,0,0,0,114,214,0,0,0,114, 217,0,0,0,114,7,0,0,0,114,7,0,0,0,114,7, - 0,0,0,114,8,0,0,0,114,202,0,0,0,236,2,0, + 0,0,0,114,8,0,0,0,114,202,0,0,0,237,2,0, 0,115,32,0,0,0,8,0,4,2,2,3,2,255,2,4, 2,255,12,3,2,2,10,1,2,6,10,1,2,14,12,1, 2,15,16,1,255,128,114,202,0,0,0,99,0,0,0,0, @@ -1142,7 +1142,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 108,0,0,0,90,13,102,105,108,101,110,97,109,101,95,98, 97,115,101,90,9,116,97,105,108,95,110,97,109,101,114,7, 0,0,0,114,7,0,0,0,114,8,0,0,0,114,193,0, - 0,0,49,3,0,0,115,10,0,0,0,18,3,16,1,14, + 0,0,50,3,0,0,115,10,0,0,0,18,3,16,1,14, 1,16,1,255,128,122,24,95,76,111,97,100,101,114,66,97, 115,105,99,115,46,105,115,95,112,97,99,107,97,103,101,99, 2,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0, @@ -1152,7 +1152,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 101,32,99,114,101,97,116,105,111,110,46,78,114,7,0,0, 0,169,2,114,130,0,0,0,114,198,0,0,0,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,218,13,99,114, - 101,97,116,101,95,109,111,100,117,108,101,57,3,0,0,243, + 101,97,116,101,95,109,111,100,117,108,101,58,3,0,0,243, 4,0,0,0,4,0,255,128,122,27,95,76,111,97,100,101, 114,66,97,115,105,99,115,46,99,114,101,97,116,101,95,109, 111,100,117,108,101,99,2,0,0,0,0,0,0,0,0,0, @@ -1172,7 +1172,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 111,118,101,100,218,4,101,120,101,99,114,143,0,0,0,41, 3,114,130,0,0,0,218,6,109,111,100,117,108,101,114,175, 0,0,0,114,7,0,0,0,114,7,0,0,0,114,8,0, - 0,0,218,11,101,120,101,99,95,109,111,100,117,108,101,60, + 0,0,218,11,101,120,101,99,95,109,111,100,117,108,101,61, 3,0,0,115,14,0,0,0,12,2,8,1,4,1,8,1, 4,255,20,2,255,128,122,25,95,76,111,97,100,101,114,66, 97,115,105,99,115,46,101,120,101,99,95,109,111,100,117,108, @@ -1184,14 +1184,14 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,218,17,95,108,111,97,100,95,109,111,100,117,108,101,95, 115,104,105,109,169,2,114,130,0,0,0,114,150,0,0,0, 114,7,0,0,0,114,7,0,0,0,114,8,0,0,0,218, - 11,108,111,97,100,95,109,111,100,117,108,101,68,3,0,0, + 11,108,111,97,100,95,109,111,100,117,108,101,69,3,0,0, 115,4,0,0,0,12,3,255,128,122,25,95,76,111,97,100, 101,114,66,97,115,105,99,115,46,108,111,97,100,95,109,111, 100,117,108,101,78,41,8,114,137,0,0,0,114,136,0,0, 0,114,138,0,0,0,114,139,0,0,0,114,193,0,0,0, 114,226,0,0,0,114,232,0,0,0,114,235,0,0,0,114, 7,0,0,0,114,7,0,0,0,114,7,0,0,0,114,8, - 0,0,0,114,222,0,0,0,44,3,0,0,115,14,0,0, + 0,0,0,114,222,0,0,0,45,3,0,0,115,14,0,0, 0,8,0,4,2,8,3,8,8,8,3,12,8,255,128,114, 222,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,3,0,0,0,64,0,0,0,115,74,0, @@ -1216,7 +1216,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 32,32,32,32,32,32,32,78,41,1,114,64,0,0,0,169, 2,114,130,0,0,0,114,58,0,0,0,114,7,0,0,0, 114,7,0,0,0,114,8,0,0,0,218,10,112,97,116,104, - 95,109,116,105,109,101,76,3,0,0,115,4,0,0,0,4, + 95,109,116,105,109,101,77,3,0,0,115,4,0,0,0,4, 6,255,128,122,23,83,111,117,114,99,101,76,111,97,100,101, 114,46,112,97,116,104,95,109,116,105,109,101,99,2,0,0, 0,0,0,0,0,0,0,0,0,2,0,0,0,4,0,0, @@ -1250,7 +1250,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 108,101,100,46,10,32,32,32,32,32,32,32,32,114,180,0, 0,0,78,41,1,114,238,0,0,0,114,237,0,0,0,114, 7,0,0,0,114,7,0,0,0,114,8,0,0,0,218,10, - 112,97,116,104,95,115,116,97,116,115,84,3,0,0,115,4, + 112,97,116,104,95,115,116,97,116,115,85,3,0,0,115,4, 0,0,0,14,12,255,128,122,23,83,111,117,114,99,101,76, 111,97,100,101,114,46,112,97,116,104,95,115,116,97,116,115, 99,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0, @@ -1274,7 +1274,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 4,114,130,0,0,0,114,119,0,0,0,90,10,99,97,99, 104,101,95,112,97,116,104,114,42,0,0,0,114,7,0,0, 0,114,7,0,0,0,114,8,0,0,0,218,15,95,99,97, - 99,104,101,95,98,121,116,101,99,111,100,101,98,3,0,0, + 99,104,101,95,98,121,116,101,99,111,100,101,99,3,0,0, 115,4,0,0,0,12,8,255,128,122,28,83,111,117,114,99, 101,76,111,97,100,101,114,46,95,99,97,99,104,101,95,98, 121,116,101,99,111,100,101,99,3,0,0,0,0,0,0,0, @@ -1291,7 +1291,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 102,105,108,101,115,46,10,32,32,32,32,32,32,32,32,78, 114,7,0,0,0,41,3,114,130,0,0,0,114,58,0,0, 0,114,42,0,0,0,114,7,0,0,0,114,7,0,0,0, - 114,8,0,0,0,114,240,0,0,0,108,3,0,0,114,227, + 114,8,0,0,0,114,240,0,0,0,109,3,0,0,114,227, 0,0,0,122,21,83,111,117,114,99,101,76,111,97,100,101, 114,46,115,101,116,95,100,97,116,97,99,2,0,0,0,0, 0,0,0,0,0,0,0,5,0,0,0,10,0,0,0,67, @@ -1311,7 +1311,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 114,187,0,0,0,41,5,114,130,0,0,0,114,150,0,0, 0,114,58,0,0,0,114,185,0,0,0,218,3,101,120,99, 114,7,0,0,0,114,7,0,0,0,114,8,0,0,0,218, - 10,103,101,116,95,115,111,117,114,99,101,115,3,0,0,115, + 10,103,101,116,95,115,111,117,114,99,101,116,3,0,0,115, 26,0,0,0,10,2,2,1,12,1,8,4,14,253,4,1, 2,1,4,255,2,1,2,255,8,128,2,255,255,128,122,23, 83,111,117,114,99,101,76,111,97,100,101,114,46,103,101,116, @@ -1334,7 +1334,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 112,105,108,101,41,4,114,130,0,0,0,114,42,0,0,0, 114,58,0,0,0,114,245,0,0,0,114,7,0,0,0,114, 7,0,0,0,114,8,0,0,0,218,14,115,111,117,114,99, - 101,95,116,111,95,99,111,100,101,125,3,0,0,115,8,0, + 101,95,116,111,95,99,111,100,101,126,3,0,0,115,8,0, 0,0,12,5,4,1,6,255,255,128,122,27,83,111,117,114, 99,101,76,111,97,100,101,114,46,115,111,117,114,99,101,95, 116,111,95,99,111,100,101,99,2,0,0,0,0,0,0,0, @@ -1412,7 +1412,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,114,17,0,0,0,90,10,98,121,116,101,115,95,100,97, 116,97,90,11,99,111,100,101,95,111,98,106,101,99,116,114, 7,0,0,0,114,7,0,0,0,114,8,0,0,0,114,228, - 0,0,0,133,3,0,0,115,170,0,0,0,10,7,4,1, + 0,0,0,134,3,0,0,115,170,0,0,0,10,7,4,1, 4,1,4,1,4,1,4,1,2,1,12,1,14,1,10,1, 2,2,14,1,14,1,6,1,12,2,2,1,14,1,14,1, 4,1,2,3,2,1,6,254,2,4,12,1,16,1,12,1, @@ -1429,7 +1429,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 238,0,0,0,114,239,0,0,0,114,241,0,0,0,114,240, 0,0,0,114,244,0,0,0,114,248,0,0,0,114,228,0, 0,0,114,7,0,0,0,114,7,0,0,0,114,7,0,0, - 0,114,8,0,0,0,114,236,0,0,0,74,3,0,0,115, + 0,114,8,0,0,0,114,236,0,0,0,75,3,0,0,115, 18,0,0,0,8,0,8,2,8,8,8,14,8,10,8,7, 14,10,12,8,255,128,114,236,0,0,0,99,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0, @@ -1457,7 +1457,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 32,32,102,105,110,100,101,114,46,78,114,170,0,0,0,41, 3,114,130,0,0,0,114,150,0,0,0,114,58,0,0,0, 114,7,0,0,0,114,7,0,0,0,114,8,0,0,0,114, - 223,0,0,0,223,3,0,0,115,6,0,0,0,6,3,10, + 223,0,0,0,224,3,0,0,115,6,0,0,0,6,3,10, 1,255,128,122,19,70,105,108,101,76,111,97,100,101,114,46, 95,95,105,110,105,116,95,95,99,2,0,0,0,0,0,0, 0,0,0,0,0,2,0,0,0,2,0,0,0,67,0,0, @@ -1466,7 +1466,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,169,2,218,9,95,95,99,108,97,115,115,95,95, 114,143,0,0,0,169,2,114,130,0,0,0,90,5,111,116, 104,101,114,114,7,0,0,0,114,7,0,0,0,114,8,0, - 0,0,218,6,95,95,101,113,95,95,229,3,0,0,243,8, + 0,0,218,6,95,95,101,113,95,95,230,3,0,0,243,8, 0,0,0,12,1,10,1,2,255,255,128,122,17,70,105,108, 101,76,111,97,100,101,114,46,95,95,101,113,95,95,99,1, 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3, @@ -1475,7 +1475,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 114,121,0,0,0,169,3,218,4,104,97,115,104,114,128,0, 0,0,114,58,0,0,0,169,1,114,130,0,0,0,114,7, 0,0,0,114,7,0,0,0,114,8,0,0,0,218,8,95, - 95,104,97,115,104,95,95,233,3,0,0,243,4,0,0,0, + 95,104,97,115,104,95,95,234,3,0,0,243,4,0,0,0, 20,1,255,128,122,19,70,105,108,101,76,111,97,100,101,114, 46,95,95,104,97,115,104,95,95,99,2,0,0,0,0,0, 0,0,0,0,0,0,2,0,0,0,3,0,0,0,3,0, @@ -1489,7 +1489,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 116,101,97,100,46,10,10,32,32,32,32,32,32,32,32,78, 41,3,218,5,115,117,112,101,114,114,254,0,0,0,114,235, 0,0,0,114,234,0,0,0,169,1,114,1,1,0,0,114, - 7,0,0,0,114,8,0,0,0,114,235,0,0,0,236,3, + 7,0,0,0,114,8,0,0,0,114,235,0,0,0,237,3, 0,0,115,4,0,0,0,16,10,255,128,122,22,70,105,108, 101,76,111,97,100,101,114,46,108,111,97,100,95,109,111,100, 117,108,101,99,2,0,0,0,0,0,0,0,0,0,0,0, @@ -1500,17 +1500,17 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 32,102,111,117,110,100,32,98,121,32,116,104,101,32,102,105, 110,100,101,114,46,78,114,62,0,0,0,114,234,0,0,0, 114,7,0,0,0,114,7,0,0,0,114,8,0,0,0,114, - 190,0,0,0,248,3,0,0,243,4,0,0,0,6,3,255, + 190,0,0,0,249,3,0,0,243,4,0,0,0,6,3,255, 128,122,23,70,105,108,101,76,111,97,100,101,114,46,103,101, 116,95,102,105,108,101,110,97,109,101,99,2,0,0,0,0, 0,0,0,0,0,0,0,3,0,0,0,8,0,0,0,67, 0,0,0,115,128,0,0,0,116,0,124,0,116,1,116,2, 102,2,131,2,114,72,116,3,160,4,116,5,124,1,131,1, - 161,1,143,24,125,2,124,2,160,6,161,0,87,0,2,0, + 161,1,143,24,125,2,124,2,160,6,161,0,87,0,99,2, 100,1,4,0,4,0,131,3,1,0,83,0,49,0,115,58, 119,1,1,0,1,0,1,0,89,0,1,0,100,1,83,0, 116,3,160,7,124,1,100,2,161,2,143,24,125,2,124,2, - 160,6,161,0,87,0,2,0,100,1,4,0,4,0,131,3, + 160,6,161,0,87,0,99,2,100,1,4,0,4,0,131,3, 1,0,83,0,49,0,115,114,119,1,1,0,1,0,1,0, 89,0,1,0,100,1,83,0,41,3,122,39,82,101,116,117, 114,110,32,116,104,101,32,100,97,116,97,32,102,114,111,109, @@ -1521,7 +1521,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 112,101,110,95,99,111,100,101,114,97,0,0,0,90,4,114, 101,97,100,114,80,0,0,0,41,3,114,130,0,0,0,114, 58,0,0,0,114,83,0,0,0,114,7,0,0,0,114,7, - 0,0,0,114,8,0,0,0,114,242,0,0,0,253,3,0, + 0,0,0,114,8,0,0,0,114,242,0,0,0,254,3,0, 0,115,16,0,0,0,14,2,16,1,22,1,20,128,14,2, 22,1,20,128,255,128,122,19,70,105,108,101,76,111,97,100, 101,114,46,103,101,116,95,100,97,116,97,99,2,0,0,0, @@ -1534,7 +1534,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 130,0,0,0,114,231,0,0,0,114,18,1,0,0,114,7, 0,0,0,114,7,0,0,0,114,8,0,0,0,218,19,103, 101,116,95,114,101,115,111,117,114,99,101,95,114,101,97,100, - 101,114,6,4,0,0,115,6,0,0,0,12,2,8,1,255, + 101,114,7,4,0,0,115,6,0,0,0,12,2,8,1,255, 128,122,30,70,105,108,101,76,111,97,100,101,114,46,103,101, 116,95,114,101,115,111,117,114,99,101,95,114,101,97,100,101, 114,41,13,114,137,0,0,0,114,136,0,0,0,114,138,0, @@ -1543,7 +1543,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 114,190,0,0,0,114,242,0,0,0,114,20,1,0,0,90, 13,95,95,99,108,97,115,115,99,101,108,108,95,95,114,7, 0,0,0,114,7,0,0,0,114,12,1,0,0,114,8,0, - 0,0,114,254,0,0,0,218,3,0,0,115,26,0,0,0, + 0,0,114,254,0,0,0,219,3,0,0,115,26,0,0,0, 8,0,4,2,8,3,8,6,8,4,2,3,14,1,2,11, 10,1,8,4,2,9,18,1,255,128,114,254,0,0,0,99, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -1566,7 +1566,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 95,109,116,105,109,101,90,7,115,116,95,115,105,122,101,41, 3,114,130,0,0,0,114,58,0,0,0,114,253,0,0,0, 114,7,0,0,0,114,7,0,0,0,114,8,0,0,0,114, - 239,0,0,0,16,4,0,0,115,6,0,0,0,8,2,14, + 239,0,0,0,17,4,0,0,115,6,0,0,0,8,2,14, 1,255,128,122,27,83,111,117,114,99,101,70,105,108,101,76, 111,97,100,101,114,46,112,97,116,104,95,115,116,97,116,115, 99,4,0,0,0,0,0,0,0,0,0,0,0,5,0,0, @@ -1576,7 +1576,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 100,101,41,2,114,126,0,0,0,114,240,0,0,0,41,5, 114,130,0,0,0,114,119,0,0,0,114,118,0,0,0,114, 42,0,0,0,114,66,0,0,0,114,7,0,0,0,114,7, - 0,0,0,114,8,0,0,0,114,241,0,0,0,21,4,0, + 0,0,0,114,8,0,0,0,114,241,0,0,0,22,4,0, 0,115,6,0,0,0,8,2,16,1,255,128,122,32,83,111, 117,114,99,101,70,105,108,101,76,111,97,100,101,114,46,95, 99,97,99,104,101,95,98,121,116,101,99,111,100,101,114,75, @@ -1612,7 +1612,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,218,6,112,97,114,101,110,116,114,108,0,0,0,114,53, 0,0,0,114,49,0,0,0,114,243,0,0,0,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,114,240,0,0, - 0,26,4,0,0,115,58,0,0,0,12,2,4,1,12,2, + 0,27,4,0,0,115,58,0,0,0,12,2,4,1,12,2, 12,1,10,1,12,254,12,4,10,1,2,1,14,1,12,1, 4,2,14,1,6,3,4,1,4,255,16,2,8,128,2,1, 12,1,18,1,14,1,8,2,2,1,18,255,8,128,2,254, @@ -1621,7 +1621,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 41,7,114,137,0,0,0,114,136,0,0,0,114,138,0,0, 0,114,139,0,0,0,114,239,0,0,0,114,241,0,0,0, 114,240,0,0,0,114,7,0,0,0,114,7,0,0,0,114, - 7,0,0,0,114,8,0,0,0,114,21,1,0,0,12,4, + 7,0,0,0,114,8,0,0,0,114,21,1,0,0,13,4, 0,0,115,12,0,0,0,8,0,4,2,8,2,8,5,18, 5,255,128,114,21,1,0,0,99,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,2,0,0,0,64,0,0, @@ -1644,7 +1644,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,41,5,114,130,0,0,0,114,150,0,0,0,114, 58,0,0,0,114,42,0,0,0,114,162,0,0,0,114,7, 0,0,0,114,7,0,0,0,114,8,0,0,0,114,228,0, - 0,0,61,4,0,0,115,24,0,0,0,10,1,10,1,2, + 0,0,62,4,0,0,115,24,0,0,0,10,1,10,1,2, 4,2,1,6,254,12,4,2,1,14,1,2,1,2,1,6, 253,255,128,122,29,83,111,117,114,99,101,108,101,115,115,70, 105,108,101,76,111,97,100,101,114,46,103,101,116,95,99,111, @@ -1654,13 +1654,13 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 97,115,32,116,104,101,114,101,32,105,115,32,110,111,32,115, 111,117,114,99,101,32,99,111,100,101,46,78,114,7,0,0, 0,114,234,0,0,0,114,7,0,0,0,114,7,0,0,0, - 114,8,0,0,0,114,244,0,0,0,77,4,0,0,114,25, + 114,8,0,0,0,114,244,0,0,0,78,4,0,0,114,25, 0,0,0,122,31,83,111,117,114,99,101,108,101,115,115,70, 105,108,101,76,111,97,100,101,114,46,103,101,116,95,115,111, 117,114,99,101,78,41,6,114,137,0,0,0,114,136,0,0, 0,114,138,0,0,0,114,139,0,0,0,114,228,0,0,0, 114,244,0,0,0,114,7,0,0,0,114,7,0,0,0,114, - 7,0,0,0,114,8,0,0,0,114,27,1,0,0,57,4, + 7,0,0,0,114,8,0,0,0,114,27,1,0,0,58,4, 0,0,115,10,0,0,0,8,0,4,2,8,2,12,16,255, 128,114,27,1,0,0,99,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,3,0,0,0,64,0,0,0,115, @@ -1682,20 +1682,20 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 100,0,83,0,114,121,0,0,0,114,170,0,0,0,41,3, 114,130,0,0,0,114,128,0,0,0,114,58,0,0,0,114, 7,0,0,0,114,7,0,0,0,114,8,0,0,0,114,223, - 0,0,0,90,4,0,0,115,6,0,0,0,6,1,10,1, + 0,0,0,91,4,0,0,115,6,0,0,0,6,1,10,1, 255,128,122,28,69,120,116,101,110,115,105,111,110,70,105,108, 101,76,111,97,100,101,114,46,95,95,105,110,105,116,95,95, 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0, 0,2,0,0,0,67,0,0,0,114,255,0,0,0,114,121, 0,0,0,114,0,1,0,0,114,2,1,0,0,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,114,3,1,0, - 0,94,4,0,0,114,4,1,0,0,122,26,69,120,116,101, + 0,95,4,0,0,114,4,1,0,0,122,26,69,120,116,101, 110,115,105,111,110,70,105,108,101,76,111,97,100,101,114,46, 95,95,101,113,95,95,99,1,0,0,0,0,0,0,0,0, 0,0,0,1,0,0,0,3,0,0,0,67,0,0,0,114, 5,1,0,0,114,121,0,0,0,114,6,1,0,0,114,8, 1,0,0,114,7,0,0,0,114,7,0,0,0,114,8,0, - 0,0,114,9,1,0,0,98,4,0,0,114,10,1,0,0, + 0,0,114,9,1,0,0,99,4,0,0,114,10,1,0,0, 122,28,69,120,116,101,110,115,105,111,110,70,105,108,101,76, 111,97,100,101,114,46,95,95,104,97,115,104,95,95,99,2, 0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,5, @@ -1712,7 +1712,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 97,109,105,99,114,160,0,0,0,114,128,0,0,0,114,58, 0,0,0,41,3,114,130,0,0,0,114,198,0,0,0,114, 231,0,0,0,114,7,0,0,0,114,7,0,0,0,114,8, - 0,0,0,114,226,0,0,0,101,4,0,0,115,16,0,0, + 0,0,0,114,226,0,0,0,102,4,0,0,115,16,0,0, 0,4,2,6,1,4,255,6,2,8,1,4,255,4,2,255, 128,122,33,69,120,116,101,110,115,105,111,110,70,105,108,101, 76,111,97,100,101,114,46,99,114,101,97,116,101,95,109,111, @@ -1730,7 +1730,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 105,99,114,160,0,0,0,114,128,0,0,0,114,58,0,0, 0,169,2,114,130,0,0,0,114,231,0,0,0,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,114,232,0,0, - 0,109,4,0,0,115,10,0,0,0,14,2,6,1,8,1, + 0,110,4,0,0,115,10,0,0,0,14,2,6,1,8,1, 8,255,255,128,122,31,69,120,116,101,110,115,105,111,110,70, 105,108,101,76,111,97,100,101,114,46,101,120,101,99,95,109, 111,100,117,108,101,99,2,0,0,0,0,0,0,0,0,0, @@ -1748,14 +1748,14 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 78,114,7,0,0,0,169,2,114,5,0,0,0,218,6,115, 117,102,102,105,120,169,1,90,9,102,105,108,101,95,110,97, 109,101,114,7,0,0,0,114,8,0,0,0,114,9,0,0, - 0,118,4,0,0,115,8,0,0,0,4,0,2,1,20,255, + 0,119,4,0,0,115,8,0,0,0,4,0,2,1,20,255, 255,128,122,49,69,120,116,101,110,115,105,111,110,70,105,108, 101,76,111,97,100,101,114,46,105,115,95,112,97,99,107,97, 103,101,46,60,108,111,99,97,108,115,62,46,60,103,101,110, 101,120,112,114,62,78,41,4,114,61,0,0,0,114,58,0, 0,0,218,3,97,110,121,114,219,0,0,0,114,234,0,0, 0,114,7,0,0,0,114,31,1,0,0,114,8,0,0,0, - 114,193,0,0,0,115,4,0,0,115,10,0,0,0,14,2, + 114,193,0,0,0,116,4,0,0,115,10,0,0,0,14,2, 12,1,2,1,8,255,255,128,122,30,69,120,116,101,110,115, 105,111,110,70,105,108,101,76,111,97,100,101,114,46,105,115, 95,112,97,99,107,97,103,101,99,2,0,0,0,0,0,0, @@ -1766,7 +1766,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 110,111,116,32,99,114,101,97,116,101,32,97,32,99,111,100, 101,32,111,98,106,101,99,116,46,78,114,7,0,0,0,114, 234,0,0,0,114,7,0,0,0,114,7,0,0,0,114,8, - 0,0,0,114,228,0,0,0,121,4,0,0,114,25,0,0, + 0,0,0,114,228,0,0,0,122,4,0,0,114,25,0,0, 0,122,28,69,120,116,101,110,115,105,111,110,70,105,108,101, 76,111,97,100,101,114,46,103,101,116,95,99,111,100,101,99, 2,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0, @@ -1776,13 +1776,13 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 115,32,104,97,118,101,32,110,111,32,115,111,117,114,99,101, 32,99,111,100,101,46,78,114,7,0,0,0,114,234,0,0, 0,114,7,0,0,0,114,7,0,0,0,114,8,0,0,0, - 114,244,0,0,0,125,4,0,0,114,25,0,0,0,122,30, + 114,244,0,0,0,126,4,0,0,114,25,0,0,0,122,30, 69,120,116,101,110,115,105,111,110,70,105,108,101,76,111,97, 100,101,114,46,103,101,116,95,115,111,117,114,99,101,99,2, 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,1, 0,0,0,67,0,0,0,114,13,1,0,0,114,14,1,0, 0,114,62,0,0,0,114,234,0,0,0,114,7,0,0,0, - 114,7,0,0,0,114,8,0,0,0,114,190,0,0,0,129, + 114,7,0,0,0,114,8,0,0,0,114,190,0,0,0,130, 4,0,0,114,15,1,0,0,122,32,69,120,116,101,110,115, 105,111,110,70,105,108,101,76,111,97,100,101,114,46,103,101, 116,95,102,105,108,101,110,97,109,101,78,41,14,114,137,0, @@ -1791,7 +1791,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 114,226,0,0,0,114,232,0,0,0,114,193,0,0,0,114, 228,0,0,0,114,244,0,0,0,114,147,0,0,0,114,190, 0,0,0,114,7,0,0,0,114,7,0,0,0,114,7,0, - 0,0,114,8,0,0,0,114,17,1,0,0,82,4,0,0, + 0,0,114,8,0,0,0,114,17,1,0,0,83,4,0,0, 115,26,0,0,0,8,0,4,2,8,6,8,4,8,4,8, 3,8,8,8,6,8,6,8,4,2,4,14,1,255,128,114, 17,1,0,0,99,0,0,0,0,0,0,0,0,0,0,0, @@ -1834,7 +1834,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 102,105,110,100,101,114,169,4,114,130,0,0,0,114,128,0, 0,0,114,58,0,0,0,90,11,112,97,116,104,95,102,105, 110,100,101,114,114,7,0,0,0,114,7,0,0,0,114,8, - 0,0,0,114,223,0,0,0,142,4,0,0,115,10,0,0, + 0,0,0,114,223,0,0,0,143,4,0,0,115,10,0,0, 0,6,1,6,1,14,1,10,1,255,128,122,23,95,78,97, 109,101,115,112,97,99,101,80,97,116,104,46,95,95,105,110, 105,116,95,95,99,1,0,0,0,0,0,0,0,0,0,0, @@ -1852,7 +1852,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 1,0,0,218,3,100,111,116,90,2,109,101,114,7,0,0, 0,114,7,0,0,0,114,8,0,0,0,218,23,95,102,105, 110,100,95,112,97,114,101,110,116,95,112,97,116,104,95,110, - 97,109,101,115,148,4,0,0,115,10,0,0,0,18,2,8, + 97,109,101,115,149,4,0,0,115,10,0,0,0,18,2,8, 1,4,2,8,3,255,128,122,38,95,78,97,109,101,115,112, 97,99,101,80,97,116,104,46,95,102,105,110,100,95,112,97, 114,101,110,116,95,112,97,116,104,95,110,97,109,101,115,99, @@ -1865,7 +1865,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 18,112,97,114,101,110,116,95,109,111,100,117,108,101,95,110, 97,109,101,90,14,112,97,116,104,95,97,116,116,114,95,110, 97,109,101,114,7,0,0,0,114,7,0,0,0,114,8,0, - 0,0,114,36,1,0,0,158,4,0,0,115,6,0,0,0, + 0,0,114,36,1,0,0,159,4,0,0,115,6,0,0,0, 12,1,16,1,255,128,122,31,95,78,97,109,101,115,112,97, 99,101,80,97,116,104,46,95,103,101,116,95,112,97,114,101, 110,116,95,112,97,116,104,99,1,0,0,0,0,0,0,0, @@ -1881,7 +1881,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 35,1,0,0,41,3,114,130,0,0,0,90,11,112,97,114, 101,110,116,95,112,97,116,104,114,198,0,0,0,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,218,12,95,114, - 101,99,97,108,99,117,108,97,116,101,162,4,0,0,115,18, + 101,99,97,108,99,117,108,97,116,101,163,4,0,0,115,18, 0,0,0,12,2,10,1,14,1,18,3,6,1,8,1,6, 1,6,1,255,128,122,27,95,78,97,109,101,115,112,97,99, 101,80,97,116,104,46,95,114,101,99,97,108,99,117,108,97, @@ -1890,7 +1890,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 116,0,124,0,160,1,161,0,131,1,83,0,114,121,0,0, 0,41,2,218,4,105,116,101,114,114,43,1,0,0,114,8, 1,0,0,114,7,0,0,0,114,7,0,0,0,114,8,0, - 0,0,218,8,95,95,105,116,101,114,95,95,175,4,0,0, + 0,0,218,8,95,95,105,116,101,114,95,95,176,4,0,0, 243,4,0,0,0,12,1,255,128,122,23,95,78,97,109,101, 115,112,97,99,101,80,97,116,104,46,95,95,105,116,101,114, 95,95,99,2,0,0,0,0,0,0,0,0,0,0,0,2, @@ -1899,7 +1899,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,169,1,114,43,1,0,0,41,2,114,130,0,0,0,218, 5,105,110,100,101,120,114,7,0,0,0,114,7,0,0,0, 114,8,0,0,0,218,11,95,95,103,101,116,105,116,101,109, - 95,95,178,4,0,0,114,47,1,0,0,122,26,95,78,97, + 95,95,179,4,0,0,114,47,1,0,0,122,26,95,78,97, 109,101,115,112,97,99,101,80,97,116,104,46,95,95,103,101, 116,105,116,101,109,95,95,99,3,0,0,0,0,0,0,0, 0,0,0,0,3,0,0,0,3,0,0,0,67,0,0,0, @@ -1907,7 +1907,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,83,0,114,121,0,0,0,41,1,114,35,1,0,0,41, 3,114,130,0,0,0,114,49,1,0,0,114,58,0,0,0, 114,7,0,0,0,114,7,0,0,0,114,8,0,0,0,218, - 11,95,95,115,101,116,105,116,101,109,95,95,181,4,0,0, + 11,95,95,115,101,116,105,116,101,109,95,95,182,4,0,0, 115,4,0,0,0,14,1,255,128,122,26,95,78,97,109,101, 115,112,97,99,101,80,97,116,104,46,95,95,115,101,116,105, 116,101,109,95,95,99,1,0,0,0,0,0,0,0,0,0, @@ -1915,7 +1915,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 1,0,0,114,121,0,0,0,41,2,114,4,0,0,0,114, 43,1,0,0,114,8,1,0,0,114,7,0,0,0,114,7, 0,0,0,114,8,0,0,0,218,7,95,95,108,101,110,95, - 95,184,4,0,0,114,47,1,0,0,122,22,95,78,97,109, + 95,185,4,0,0,114,47,1,0,0,122,22,95,78,97,109, 101,115,112,97,99,101,80,97,116,104,46,95,95,108,101,110, 95,95,99,1,0,0,0,0,0,0,0,0,0,0,0,1, 0,0,0,3,0,0,0,67,0,0,0,243,12,0,0,0, @@ -1923,7 +1923,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 20,95,78,97,109,101,115,112,97,99,101,80,97,116,104,40, 123,33,114,125,41,41,2,114,77,0,0,0,114,35,1,0, 0,114,8,1,0,0,114,7,0,0,0,114,7,0,0,0, - 114,8,0,0,0,218,8,95,95,114,101,112,114,95,95,187, + 114,8,0,0,0,218,8,95,95,114,101,112,114,95,95,188, 4,0,0,114,47,1,0,0,122,23,95,78,97,109,101,115, 112,97,99,101,80,97,116,104,46,95,95,114,101,112,114,95, 95,99,2,0,0,0,0,0,0,0,0,0,0,0,2,0, @@ -1931,7 +1931,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 1,124,0,160,0,161,0,118,0,83,0,114,121,0,0,0, 114,48,1,0,0,169,2,114,130,0,0,0,218,4,105,116, 101,109,114,7,0,0,0,114,7,0,0,0,114,8,0,0, - 0,218,12,95,95,99,111,110,116,97,105,110,115,95,95,190, + 0,218,12,95,95,99,111,110,116,97,105,110,115,95,95,191, 4,0,0,114,47,1,0,0,122,27,95,78,97,109,101,115, 112,97,99,101,80,97,116,104,46,95,95,99,111,110,116,97, 105,110,115,95,95,99,2,0,0,0,0,0,0,0,0,0, @@ -1939,7 +1939,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,124,0,106,0,160,1,124,1,161,1,1,0,100, 0,83,0,114,121,0,0,0,41,2,114,35,1,0,0,114, 197,0,0,0,114,55,1,0,0,114,7,0,0,0,114,7, - 0,0,0,114,8,0,0,0,114,197,0,0,0,193,4,0, + 0,0,0,114,8,0,0,0,114,197,0,0,0,194,4,0, 0,243,4,0,0,0,16,1,255,128,122,21,95,78,97,109, 101,115,112,97,99,101,80,97,116,104,46,97,112,112,101,110, 100,78,41,15,114,137,0,0,0,114,136,0,0,0,114,138, @@ -1948,7 +1948,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,114,50,1,0,0,114,51,1,0,0,114,52,1,0,0, 114,54,1,0,0,114,57,1,0,0,114,197,0,0,0,114, 7,0,0,0,114,7,0,0,0,114,7,0,0,0,114,8, - 0,0,0,114,33,1,0,0,135,4,0,0,115,28,0,0, + 0,0,0,114,33,1,0,0,136,4,0,0,115,28,0,0, 0,8,0,4,1,8,6,8,6,8,10,8,4,8,13,8, 3,8,3,8,3,8,3,8,3,12,3,255,128,114,33,1, 0,0,99,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -1965,7 +1965,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 124,3,131,3,124,0,95,1,100,0,83,0,114,121,0,0, 0,41,2,114,33,1,0,0,114,35,1,0,0,114,39,1, 0,0,114,7,0,0,0,114,7,0,0,0,114,8,0,0, - 0,114,223,0,0,0,199,4,0,0,115,4,0,0,0,18, + 0,114,223,0,0,0,200,4,0,0,115,4,0,0,0,18, 1,255,128,122,25,95,78,97,109,101,115,112,97,99,101,76, 111,97,100,101,114,46,95,95,105,110,105,116,95,95,99,1, 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3, @@ -1981,21 +1981,21 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 125,32,40,110,97,109,101,115,112,97,99,101,41,62,78,41, 2,114,77,0,0,0,114,137,0,0,0,41,1,114,231,0, 0,0,114,7,0,0,0,114,7,0,0,0,114,8,0,0, - 0,218,11,109,111,100,117,108,101,95,114,101,112,114,202,4, + 0,218,11,109,111,100,117,108,101,95,114,101,112,114,203,4, 0,0,115,4,0,0,0,12,7,255,128,122,28,95,78,97, 109,101,115,112,97,99,101,76,111,97,100,101,114,46,109,111, 100,117,108,101,95,114,101,112,114,99,2,0,0,0,0,0, 0,0,0,0,0,0,2,0,0,0,1,0,0,0,67,0, 0,0,114,24,0,0,0,41,2,78,84,114,7,0,0,0, 114,234,0,0,0,114,7,0,0,0,114,7,0,0,0,114, - 8,0,0,0,114,193,0,0,0,211,4,0,0,243,4,0, + 8,0,0,0,114,193,0,0,0,212,4,0,0,243,4,0, 0,0,4,1,255,128,122,27,95,78,97,109,101,115,112,97, 99,101,76,111,97,100,101,114,46,105,115,95,112,97,99,107, 97,103,101,99,2,0,0,0,0,0,0,0,0,0,0,0, 2,0,0,0,1,0,0,0,67,0,0,0,114,24,0,0, 0,41,2,78,114,10,0,0,0,114,7,0,0,0,114,234, 0,0,0,114,7,0,0,0,114,7,0,0,0,114,8,0, - 0,0,114,244,0,0,0,214,4,0,0,114,61,1,0,0, + 0,0,114,244,0,0,0,215,4,0,0,114,61,1,0,0, 122,27,95,78,97,109,101,115,112,97,99,101,76,111,97,100, 101,114,46,103,101,116,95,115,111,117,114,99,101,99,2,0, 0,0,0,0,0,0,0,0,0,0,2,0,0,0,6,0, @@ -2004,20 +2004,20 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,122,8,60,115,116,114,105,110,103,62,114,230,0, 0,0,84,41,1,114,246,0,0,0,41,1,114,247,0,0, 0,114,234,0,0,0,114,7,0,0,0,114,7,0,0,0, - 114,8,0,0,0,114,228,0,0,0,217,4,0,0,114,58, + 114,8,0,0,0,114,228,0,0,0,218,4,0,0,114,58, 1,0,0,122,25,95,78,97,109,101,115,112,97,99,101,76, 111,97,100,101,114,46,103,101,116,95,99,111,100,101,99,2, 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,1, 0,0,0,67,0,0,0,114,24,0,0,0,114,224,0,0, 0,114,7,0,0,0,114,225,0,0,0,114,7,0,0,0, - 114,7,0,0,0,114,8,0,0,0,114,226,0,0,0,220, + 114,7,0,0,0,114,8,0,0,0,114,226,0,0,0,221, 4,0,0,114,227,0,0,0,122,30,95,78,97,109,101,115, 112,97,99,101,76,111,97,100,101,114,46,99,114,101,97,116, 101,95,109,111,100,117,108,101,99,2,0,0,0,0,0,0, 0,0,0,0,0,2,0,0,0,1,0,0,0,67,0,0, 0,115,4,0,0,0,100,0,83,0,114,121,0,0,0,114, 7,0,0,0,114,28,1,0,0,114,7,0,0,0,114,7, - 0,0,0,114,8,0,0,0,114,232,0,0,0,223,4,0, + 0,0,0,114,8,0,0,0,114,232,0,0,0,224,4,0, 0,114,61,1,0,0,122,28,95,78,97,109,101,115,112,97, 99,101,76,111,97,100,101,114,46,101,120,101,99,95,109,111, 100,117,108,101,99,2,0,0,0,0,0,0,0,0,0,0, @@ -2035,7 +2035,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 32,112,97,116,104,32,123,33,114,125,78,41,4,114,146,0, 0,0,114,160,0,0,0,114,35,1,0,0,114,233,0,0, 0,114,234,0,0,0,114,7,0,0,0,114,7,0,0,0, - 114,8,0,0,0,114,235,0,0,0,226,4,0,0,115,10, + 114,8,0,0,0,114,235,0,0,0,227,4,0,0,115,10, 0,0,0,6,7,4,1,4,255,12,3,255,128,122,28,95, 78,97,109,101,115,112,97,99,101,76,111,97,100,101,114,46, 108,111,97,100,95,109,111,100,117,108,101,99,2,0,0,0, @@ -2047,7 +2047,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,114,62,1,0,0,114,35,1,0,0,41,3,114,130,0, 0,0,114,231,0,0,0,114,62,1,0,0,114,7,0,0, 0,114,7,0,0,0,114,8,0,0,0,114,20,1,0,0, - 238,4,0,0,115,6,0,0,0,12,1,10,1,255,128,122, + 239,4,0,0,115,6,0,0,0,12,1,10,1,255,128,122, 36,95,78,97,109,101,115,112,97,99,101,76,111,97,100,101, 114,46,103,101,116,95,114,101,115,111,117,114,99,101,95,114, 101,97,100,101,114,78,41,13,114,137,0,0,0,114,136,0, @@ -2056,7 +2056,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 114,228,0,0,0,114,226,0,0,0,114,232,0,0,0,114, 235,0,0,0,114,20,1,0,0,114,7,0,0,0,114,7, 0,0,0,114,7,0,0,0,114,8,0,0,0,114,59,1, - 0,0,198,4,0,0,115,24,0,0,0,8,0,8,1,2, + 0,0,199,4,0,0,115,24,0,0,0,8,0,8,1,2, 3,10,1,8,8,8,3,8,3,8,3,8,3,8,3,12, 12,255,128,114,59,1,0,0,99,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,4,0,0,0,64,0,0, @@ -2093,7 +2093,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 5,105,116,101,109,115,114,140,0,0,0,114,64,1,0,0, 41,2,114,128,0,0,0,218,6,102,105,110,100,101,114,114, 7,0,0,0,114,7,0,0,0,114,8,0,0,0,114,64, - 1,0,0,249,4,0,0,115,16,0,0,0,22,4,8,1, + 1,0,0,250,4,0,0,115,16,0,0,0,22,4,8,1, 10,1,10,1,8,1,2,128,4,252,255,128,122,28,80,97, 116,104,70,105,110,100,101,114,46,105,110,118,97,108,105,100, 97,116,101,95,99,97,99,104,101,115,99,1,0,0,0,0, @@ -2101,7 +2101,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,115,76,0,0,0,116,0,106,1,100,1,117,1, 114,28,116,0,106,1,115,28,116,2,160,3,100,2,116,4, 161,2,1,0,116,0,106,1,68,0,93,34,125,1,122,14, - 124,1,124,0,131,1,87,0,2,0,1,0,83,0,4,0, + 124,1,124,0,131,1,87,0,99,2,1,0,83,0,4,0, 116,5,121,74,1,0,1,0,1,0,89,0,113,34,100,1, 83,0,119,0,41,3,122,46,83,101,97,114,99,104,32,115, 121,115,46,112,97,116,104,95,104,111,111,107,115,32,102,111, @@ -2113,7 +2113,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,114,129,0,0,0,41,2,114,58,0,0,0,90,4, 104,111,111,107,114,7,0,0,0,114,7,0,0,0,114,8, 0,0,0,218,11,95,112,97,116,104,95,104,111,111,107,115, - 3,5,0,0,115,20,0,0,0,16,3,12,1,10,1,2, + 4,5,0,0,115,20,0,0,0,16,3,12,1,10,1,2, 1,14,1,12,1,4,1,4,2,2,253,255,128,122,22,80, 97,116,104,70,105,110,100,101,114,46,95,112,97,116,104,95, 104,111,111,107,115,99,2,0,0,0,0,0,0,0,0,0, @@ -2145,7 +2145,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,114,58,0,0,0,114,68,1,0,0,114,7,0,0, 0,114,7,0,0,0,114,8,0,0,0,218,20,95,112,97, 116,104,95,105,109,112,111,114,116,101,114,95,99,97,99,104, - 101,16,5,0,0,115,30,0,0,0,8,8,2,1,12,1, + 101,17,5,0,0,115,30,0,0,0,8,8,2,1,12,1, 12,1,6,3,2,1,12,1,4,4,12,253,10,1,12,1, 4,1,2,253,2,250,255,128,122,31,80,97,116,104,70,105, 110,100,101,114,46,95,112,97,116,104,95,105,109,112,111,114, @@ -2163,7 +2163,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,114,68,1,0,0,114,151,0,0,0,114,152,0,0, 0,114,198,0,0,0,114,7,0,0,0,114,7,0,0,0, 114,8,0,0,0,218,16,95,108,101,103,97,99,121,95,103, - 101,116,95,115,112,101,99,38,5,0,0,115,20,0,0,0, + 101,116,95,115,112,101,99,39,5,0,0,115,20,0,0,0, 10,4,16,1,10,2,4,1,8,1,12,1,12,1,6,1, 4,1,255,128,122,27,80,97,116,104,70,105,110,100,101,114, 46,95,108,101,103,97,99,121,95,103,101,116,95,115,112,101, @@ -2175,7 +2175,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 124,6,100,2,131,2,114,70,124,6,160,5,124,1,124,3, 161,2,125,7,110,12,124,0,160,6,124,1,124,6,161,2, 125,7,124,7,100,1,117,0,114,92,113,8,124,7,106,7, - 100,1,117,1,114,110,124,7,2,0,1,0,83,0,124,7, + 100,1,117,1,114,110,124,7,99,2,1,0,83,0,124,7, 106,8,125,8,124,8,100,1,117,0,114,132,116,9,100,3, 131,1,130,1,124,4,160,10,124,8,161,1,1,0,113,8, 116,11,160,12,124,1,100,1,161,2,125,7,124,4,124,7, @@ -2194,7 +2194,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 14,110,97,109,101,115,112,97,99,101,95,112,97,116,104,90, 5,101,110,116,114,121,114,68,1,0,0,114,198,0,0,0, 114,152,0,0,0,114,7,0,0,0,114,7,0,0,0,114, - 8,0,0,0,218,9,95,103,101,116,95,115,112,101,99,53, + 8,0,0,0,218,9,95,103,101,116,95,115,112,101,99,54, 5,0,0,115,44,0,0,0,4,5,8,1,14,1,2,1, 10,1,8,1,10,1,14,1,12,2,8,1,2,1,10,1, 8,1,6,1,8,1,8,1,10,5,2,128,12,2,6,1, @@ -2222,7 +2222,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 209,0,0,0,114,150,0,0,0,114,58,0,0,0,114,213, 0,0,0,114,198,0,0,0,114,76,1,0,0,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,114,214,0,0, - 0,85,5,0,0,115,28,0,0,0,8,6,6,1,14,1, + 0,86,5,0,0,115,28,0,0,0,8,6,6,1,14,1, 8,1,4,1,10,1,6,1,4,1,6,3,16,1,4,1, 4,2,4,2,255,128,122,20,80,97,116,104,70,105,110,100, 101,114,46,102,105,110,100,95,115,112,101,99,99,3,0,0, @@ -2242,7 +2242,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 99,40,41,32,105,110,115,116,101,97,100,46,10,10,32,32, 32,32,32,32,32,32,78,114,215,0,0,0,114,216,0,0, 0,114,7,0,0,0,114,7,0,0,0,114,8,0,0,0, - 114,217,0,0,0,109,5,0,0,115,10,0,0,0,12,8, + 114,217,0,0,0,110,5,0,0,115,10,0,0,0,12,8, 8,1,4,1,6,1,255,128,122,22,80,97,116,104,70,105, 110,100,101,114,46,102,105,110,100,95,109,111,100,117,108,101, 99,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0, @@ -2274,7 +2274,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 105,115,116,114,105,98,117,116,105,111,110,115,41,3,114,131, 0,0,0,114,132,0,0,0,114,78,1,0,0,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,114,79,1,0, - 0,122,5,0,0,115,6,0,0,0,12,10,16,1,255,128, + 0,123,5,0,0,115,6,0,0,0,12,10,16,1,255,128, 122,29,80,97,116,104,70,105,110,100,101,114,46,102,105,110, 100,95,100,105,115,116,114,105,98,117,116,105,111,110,115,41, 1,78,41,2,78,78,41,1,78,41,14,114,137,0,0,0, @@ -2283,7 +2283,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,114,73,1,0,0,114,74,1,0,0,114,77,1, 0,0,114,214,0,0,0,114,217,0,0,0,114,79,1,0, 0,114,7,0,0,0,114,7,0,0,0,114,7,0,0,0, - 114,8,0,0,0,114,63,1,0,0,245,4,0,0,115,38, + 114,8,0,0,0,114,63,1,0,0,246,4,0,0,115,38, 0,0,0,8,0,4,2,2,2,10,1,2,9,10,1,2, 12,10,1,2,21,10,1,2,14,12,1,2,31,12,1,2, 23,12,1,2,12,14,1,255,128,114,63,1,0,0,99,0, @@ -2328,7 +2328,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 124,0,93,14,125,1,124,1,136,0,102,2,86,0,1,0, 113,2,100,0,83,0,114,121,0,0,0,114,7,0,0,0, 114,29,1,0,0,169,1,114,151,0,0,0,114,7,0,0, - 0,114,8,0,0,0,114,9,0,0,0,151,5,0,0,114, + 0,114,8,0,0,0,114,9,0,0,0,152,5,0,0,114, 14,0,0,0,122,38,70,105,108,101,70,105,110,100,101,114, 46,95,95,105,110,105,116,95,95,46,60,108,111,99,97,108, 115,62,46,60,103,101,110,101,120,112,114,62,114,86,0,0, @@ -2340,7 +2340,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 101,41,5,114,130,0,0,0,114,58,0,0,0,218,14,108, 111,97,100,101,114,95,100,101,116,97,105,108,115,90,7,108, 111,97,100,101,114,115,114,200,0,0,0,114,7,0,0,0, - 114,81,1,0,0,114,8,0,0,0,114,223,0,0,0,145, + 114,81,1,0,0,114,8,0,0,0,114,223,0,0,0,146, 5,0,0,115,18,0,0,0,4,4,12,1,26,1,6,1, 10,2,6,1,8,1,12,1,255,128,122,19,70,105,108,101, 70,105,110,100,101,114,46,95,95,105,110,105,116,95,95,99, @@ -2351,7 +2351,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 111,114,121,32,109,116,105,109,101,46,114,116,0,0,0,78, 41,1,114,83,1,0,0,114,8,1,0,0,114,7,0,0, 0,114,7,0,0,0,114,8,0,0,0,114,64,1,0,0, - 159,5,0,0,114,69,0,0,0,122,28,70,105,108,101,70, + 160,5,0,0,114,69,0,0,0,122,28,70,105,108,101,70, 105,110,100,101,114,46,105,110,118,97,108,105,100,97,116,101, 95,99,97,99,104,101,115,99,2,0,0,0,0,0,0,0, 0,0,0,0,3,0,0,0,3,0,0,0,67,0,0,0, @@ -2373,7 +2373,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 32,32,32,32,32,32,32,32,78,41,3,114,214,0,0,0, 114,151,0,0,0,114,189,0,0,0,41,3,114,130,0,0, 0,114,150,0,0,0,114,198,0,0,0,114,7,0,0,0, - 114,7,0,0,0,114,8,0,0,0,114,148,0,0,0,165, + 114,7,0,0,0,114,8,0,0,0,114,148,0,0,0,166, 5,0,0,115,10,0,0,0,10,7,8,1,8,1,16,1, 255,128,122,22,70,105,108,101,70,105,110,100,101,114,46,102, 105,110,100,95,108,111,97,100,101,114,99,6,0,0,0,0, @@ -2384,7 +2384,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,41,7,114,130,0,0,0,114,199,0,0,0,114,150,0, 0,0,114,58,0,0,0,90,4,115,109,115,108,114,213,0, 0,0,114,151,0,0,0,114,7,0,0,0,114,7,0,0, - 0,114,8,0,0,0,114,77,1,0,0,177,5,0,0,115, + 0,114,8,0,0,0,114,77,1,0,0,178,5,0,0,115, 10,0,0,0,10,1,8,1,2,1,6,255,255,128,122,20, 70,105,108,101,70,105,110,100,101,114,46,95,103,101,116,95, 115,112,101,99,78,99,3,0,0,0,0,0,0,0,0,0, @@ -2401,14 +2401,14 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,106,14,68,0,93,58,92,2,125,9,125,10,100,5,124, 9,23,0,125,11,116,13,124,8,124,11,131,2,125,12,116, 15,124,12,131,1,114,204,124,0,160,16,124,10,124,1,124, - 12,124,8,103,1,124,2,161,5,2,0,1,0,83,0,113, + 12,124,8,103,1,124,2,161,5,99,2,1,0,83,0,113, 146,116,17,124,8,131,1,125,3,124,0,106,14,68,0,93, 86,92,2,125,9,125,10,116,13,124,0,106,2,124,4,124, 9,23,0,131,2,125,12,116,18,106,19,100,6,124,12,100, 3,100,7,141,3,1,0,124,7,124,9,23,0,124,6,118, 0,144,1,114,50,116,15,124,12,131,1,144,1,114,50,124, - 0,160,16,124,10,124,1,124,12,100,8,124,2,161,5,2, - 0,1,0,83,0,113,220,124,3,144,1,114,94,116,18,160, + 0,160,16,124,10,124,1,124,12,100,8,124,2,161,5,99, + 2,1,0,83,0,113,220,124,3,144,1,114,94,116,18,160, 19,100,9,124,8,161,2,1,0,116,18,160,20,124,1,100, 8,161,2,125,13,124,8,103,1,124,13,95,21,124,13,83, 0,100,8,83,0,119,0,41,10,122,111,84,114,121,32,116, @@ -2439,7 +2439,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,114,199,0,0,0,90,13,105,110,105,116,95,102,105,108, 101,110,97,109,101,90,9,102,117,108,108,95,112,97,116,104, 114,198,0,0,0,114,7,0,0,0,114,7,0,0,0,114, - 8,0,0,0,114,214,0,0,0,182,5,0,0,115,80,0, + 8,0,0,0,114,214,0,0,0,183,5,0,0,115,80,0, 0,0,4,5,14,1,2,1,24,1,14,1,6,1,10,1, 8,1,6,1,6,2,6,1,10,1,6,2,4,1,8,2, 12,1,14,1,8,1,10,1,8,1,24,1,2,255,8,5, @@ -2471,7 +2471,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 1,124,1,160,0,161,0,146,2,113,4,83,0,114,7,0, 0,0,41,1,114,117,0,0,0,41,2,114,5,0,0,0, 90,2,102,110,114,7,0,0,0,114,7,0,0,0,114,8, - 0,0,0,114,13,0,0,0,3,6,0,0,115,4,0,0, + 0,0,0,114,13,0,0,0,4,6,0,0,115,4,0,0, 0,20,0,255,128,122,41,70,105,108,101,70,105,110,100,101, 114,46,95,102,105,108,108,95,99,97,99,104,101,46,60,108, 111,99,97,108,115,62,46,60,115,101,116,99,111,109,112,62, @@ -2488,7 +2488,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 95,99,111,110,116,101,110,116,115,114,56,1,0,0,114,128, 0,0,0,114,40,1,0,0,114,30,1,0,0,90,8,110, 101,119,95,110,97,109,101,114,7,0,0,0,114,7,0,0, - 0,114,8,0,0,0,114,88,1,0,0,230,5,0,0,115, + 0,114,8,0,0,0,114,88,1,0,0,231,5,0,0,115, 40,0,0,0,6,2,2,1,22,1,18,1,6,3,12,3, 12,1,6,7,8,1,16,1,4,1,18,1,4,2,12,1, 6,1,12,1,20,1,4,255,2,233,255,128,122,22,70,105, @@ -2527,7 +2527,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 129,0,0,0,114,62,0,0,0,169,2,114,209,0,0,0, 114,87,1,0,0,114,7,0,0,0,114,8,0,0,0,218, 24,112,97,116,104,95,104,111,111,107,95,102,111,114,95,70, - 105,108,101,70,105,110,100,101,114,15,6,0,0,115,8,0, + 105,108,101,70,105,110,100,101,114,16,6,0,0,115,8,0, 0,0,8,2,12,1,16,1,255,128,122,54,70,105,108,101, 70,105,110,100,101,114,46,112,97,116,104,95,104,111,111,107, 46,60,108,111,99,97,108,115,62,46,112,97,116,104,95,104, @@ -2535,7 +2535,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 101,114,78,114,7,0,0,0,41,3,114,209,0,0,0,114, 87,1,0,0,114,93,1,0,0,114,7,0,0,0,114,92, 1,0,0,114,8,0,0,0,218,9,112,97,116,104,95,104, - 111,111,107,5,6,0,0,115,6,0,0,0,14,10,4,6, + 111,111,107,6,6,0,0,115,6,0,0,0,14,10,4,6, 255,128,122,20,70,105,108,101,70,105,110,100,101,114,46,112, 97,116,104,95,104,111,111,107,99,1,0,0,0,0,0,0, 0,0,0,0,0,1,0,0,0,3,0,0,0,67,0,0, @@ -2543,7 +2543,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 105,110,100,101,114,40,123,33,114,125,41,41,2,114,77,0, 0,0,114,58,0,0,0,114,8,1,0,0,114,7,0,0, 0,114,7,0,0,0,114,8,0,0,0,114,54,1,0,0, - 23,6,0,0,114,47,1,0,0,122,19,70,105,108,101,70, + 24,6,0,0,114,47,1,0,0,122,19,70,105,108,101,70, 105,110,100,101,114,46,95,95,114,101,112,114,95,95,41,1, 78,41,15,114,137,0,0,0,114,136,0,0,0,114,138,0, 0,0,114,139,0,0,0,114,223,0,0,0,114,64,1,0, @@ -2551,7 +2551,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 114,77,1,0,0,114,214,0,0,0,114,88,1,0,0,114, 221,0,0,0,114,94,1,0,0,114,54,1,0,0,114,7, 0,0,0,114,7,0,0,0,114,7,0,0,0,114,8,0, - 0,0,114,80,1,0,0,136,5,0,0,115,26,0,0,0, + 0,0,114,80,1,0,0,137,5,0,0,115,26,0,0,0, 8,0,4,2,8,7,8,14,4,4,8,2,8,12,10,5, 8,48,2,31,10,1,12,17,255,128,114,80,1,0,0,99, 4,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0, @@ -2575,7 +2575,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 97,116,104,110,97,109,101,114,151,0,0,0,114,198,0,0, 0,114,7,0,0,0,114,7,0,0,0,114,8,0,0,0, 218,14,95,102,105,120,95,117,112,95,109,111,100,117,108,101, - 29,6,0,0,115,38,0,0,0,10,2,10,1,4,1,4, + 30,6,0,0,115,38,0,0,0,10,2,10,1,4,1,4, 1,8,1,8,1,12,1,10,2,4,1,14,1,2,1,8, 1,8,1,8,1,14,1,12,1,6,2,2,254,255,128,114, 99,1,0,0,99,0,0,0,0,0,0,0,0,0,0,0, @@ -2595,7 +2595,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 41,3,90,10,101,120,116,101,110,115,105,111,110,115,90,6, 115,111,117,114,99,101,90,8,98,121,116,101,99,111,100,101, 114,7,0,0,0,114,7,0,0,0,114,8,0,0,0,114, - 195,0,0,0,52,6,0,0,115,10,0,0,0,12,5,8, + 195,0,0,0,53,6,0,0,115,10,0,0,0,12,5,8, 1,8,1,10,1,255,128,114,195,0,0,0,99,1,0,0, 0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0, 0,67,0,0,0,115,8,0,0,0,124,0,97,0,100,0, @@ -2603,7 +2603,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 218,17,95,98,111,111,116,115,116,114,97,112,95,109,111,100, 117,108,101,114,7,0,0,0,114,7,0,0,0,114,8,0, 0,0,218,21,95,115,101,116,95,98,111,111,116,115,116,114, - 97,112,95,109,111,100,117,108,101,63,6,0,0,115,4,0, + 97,112,95,109,111,100,117,108,101,64,6,0,0,115,4,0, 0,0,8,2,255,128,114,102,1,0,0,99,1,0,0,0, 0,0,0,0,0,0,0,0,2,0,0,0,4,0,0,0, 67,0,0,0,115,50,0,0,0,116,0,124,0,131,1,1, @@ -2619,7 +2619,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 1,0,0,41,2,114,101,1,0,0,90,17,115,117,112,112, 111,114,116,101,100,95,108,111,97,100,101,114,115,114,7,0, 0,0,114,7,0,0,0,114,8,0,0,0,218,8,95,105, - 110,115,116,97,108,108,68,6,0,0,115,10,0,0,0,8, + 110,115,116,97,108,108,69,6,0,0,115,10,0,0,0,8, 2,6,1,20,1,16,1,255,128,114,104,1,0,0,41,1, 114,75,0,0,0,41,1,78,41,3,78,78,78,41,2,114, 0,0,0,0,114,0,0,0,0,41,1,84,41,1,78,41, @@ -2662,7 +2662,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 22,2,8,1,10,1,14,1,4,4,4,1,2,1,2,1, 4,255,8,4,6,16,8,3,8,5,8,5,8,6,8,6, 8,12,8,10,8,9,8,5,8,7,10,9,10,22,0,127, - 16,25,12,1,4,2,4,1,6,2,6,1,10,1,8,2, + 16,26,12,1,4,2,4,1,6,2,6,1,10,1,8,2, 6,2,8,2,16,2,8,71,8,40,8,19,8,12,8,12, 8,31,8,17,8,33,8,28,10,24,10,13,10,10,8,11, 6,14,4,3,2,1,12,255,14,68,14,64,16,30,0,127, diff --git a/Python/importlib_zipimport.h b/Python/importlib_zipimport.h index 9af8d7b10489da..e1238bd019eb58 100644 --- a/Python/importlib_zipimport.h +++ b/Python/importlib_zipimport.h @@ -136,7 +136,7 @@ const unsigned char _Py_M__zipimport[] = { 15,124,1,60,0,89,0,124,7,124,0,95,18,124,1,124, 0,95,19,116,8,106,20,124,3,100,0,100,0,100,8,133, 3,25,0,142,0,124,0,95,21,124,0,106,21,144,1,114, - 32,124,0,4,0,106,21,116,7,55,0,2,0,95,21,100, + 32,124,0,4,0,106,21,116,7,55,0,99,2,95,21,100, 0,83,0,100,0,83,0,119,0,119,0,41,9,78,114,0, 0,0,0,122,21,97,114,99,104,105,118,101,32,112,97,116, 104,32,105,115,32,101,109,112,116,121,169,1,218,4,112,97, @@ -588,7 +588,7 @@ const unsigned char _Py_M__zipimport[] = { 0,0,4,0,0,0,67,0,0,0,115,56,0,0,0,116, 0,124,0,124,1,131,2,125,2,116,1,68,0,93,36,92, 3,125,3,125,4,125,5,124,2,124,3,23,0,125,6,124, - 6,124,0,106,2,118,0,114,50,124,5,2,0,1,0,83, + 6,124,0,106,2,118,0,114,50,124,5,99,2,1,0,83, 0,113,14,100,0,83,0,114,93,0,0,0,41,3,114,36, 0,0,0,218,16,95,122,105,112,95,115,101,97,114,99,104, 111,114,100,101,114,114,28,0,0,0,41,7,114,32,0,0, @@ -998,7 +998,7 @@ const unsigned char _Py_M__zipimport[] = { 0,89,0,100,0,125,12,126,12,110,18,100,0,125,12,126, 12,119,1,116,11,124,9,124,10,131,2,125,11,124,11,100, 0,117,0,114,202,113,18,124,8,100,4,25,0,125,9,124, - 11,124,6,124,9,102,3,2,0,1,0,83,0,124,3,114, + 11,124,6,124,9,102,3,99,2,1,0,83,0,124,3,114, 252,100,5,124,3,155,0,157,2,125,13,116,12,124,13,124, 1,100,6,141,2,124,3,130,2,116,12,100,7,124,1,155, 2,157,2,124,1,100,6,141,2,130,1,119,0,119,0,41, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 692442ac8c1b82..5d118412642156 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -1,11 +1,11 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&TARGET_POP_TOP, - &&TARGET_ROT_TWO, - &&TARGET_ROT_THREE, + &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_DUP_TOP, &&TARGET_DUP_TOP_TWO, - &&TARGET_ROT_FOUR, + &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&TARGET_NOP, @@ -98,7 +98,7 @@ static void *opcode_targets[256] = { &&TARGET_DELETE_ATTR, &&TARGET_STORE_GLOBAL, &&TARGET_DELETE_GLOBAL, - &&_unknown_opcode, + &&TARGET_ROTATE, &&TARGET_LOAD_CONST, &&TARGET_LOAD_NAME, &&TARGET_BUILD_TUPLE, From 125e8e4ebd03f5dbbc11a9366c17d2c1d9a2de92 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 1 Apr 2021 16:43:49 -0700 Subject: [PATCH 02/47] Get "as" assignments working with deferred stores. --- Python/compile.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index d5f52ad1a97e63..8901d6343bc1aa 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -205,6 +205,7 @@ struct compiler { typedef struct { PyObject *stores; int allow_irrefutable; + Py_ssize_t underneath; } pattern_context; static int compiler_enter_scope(struct compiler *, identifier, int, void *, int); @@ -5499,7 +5500,10 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) } } RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); - RETURN_IF_FALSE(compiler_nameop(c, n, Store)); + if (pc->underneath) { + ADDOP_I(c, ROTATE, pc->underneath + 1); + } + // RETURN_IF_FALSE(compiler_nameop(c, n, Store)); return 1; } @@ -5639,19 +5643,13 @@ compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) assert(p->kind == MatchAs_kind); basicblock *end, *fail_pop_1; RETURN_IF_FALSE(end = compiler_new_block(c)); - RETURN_IF_FALSE(fail_pop_1 = compiler_new_block(c)); // Need to make a copy for (possibly) storing later: ADDOP(c, DUP_TOP); RETURN_IF_FALSE(compiler_pattern(c, p->v.MatchAs.pattern, pc)); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); + ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, end); NEXT_BLOCK(c); RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.MatchAs.name, pc)); ADDOP_LOAD_CONST(c, Py_True); - ADDOP_JUMP(c, JUMP_FORWARD, end); - compiler_use_next_block(c, fail_pop_1); - // Need to pop that unused copy from before: - ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_False); compiler_use_next_block(c, end); return 1; } @@ -6063,7 +6061,7 @@ static int compiler_match(struct compiler *c, stmt_ty s) { VISIT(c, expr, s->v.Match.subject); - basicblock *next, *end; + basicblock *next, *fail_guard, *end; RETURN_IF_FALSE(end = compiler_new_block(c)); Py_ssize_t cases = asdl_seq_LEN(s->v.Match.cases); assert(cases); @@ -6079,20 +6077,29 @@ compiler_match(struct compiler *c, stmt_ty s) m = asdl_seq_GET(s->v.Match.cases, i); SET_LOC(c, m->pattern); RETURN_IF_FALSE(next = compiler_new_block(c)); + RETURN_IF_FALSE(fail_guard = compiler_new_block(c)); // If pc.allow_irrefutable is 0, any name captures against our subject // will raise. Irrefutable cases must be either guarded, last, or both: pc.allow_irrefutable = m->guard != NULL || i == cases - 1; + pc.underneath = 0; // Only copy the subject if we're *not* on the last case: if (i != cases - has_default - 1) { ADDOP(c, DUP_TOP); } int result = compiler_pattern(c, m->pattern, &pc); - Py_CLEAR(pc.stores); + assert(!pc.underneath); RETURN_IF_FALSE(result); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, next); NEXT_BLOCK(c); + if (pc.stores) { + Py_ssize_t i = PyList_GET_SIZE(pc.stores); + while (i--) { + PyObject *n = PyList_GET_ITEM(pc.stores, i); + RETURN_IF_FALSE(compiler_nameop(c, n, Store)); + } + } if (m->guard) { - RETURN_IF_FALSE(compiler_jump_if(c, m->guard, next, 0)); + RETURN_IF_FALSE(compiler_jump_if(c, m->guard, fail_guard, 0)); } // Success! Pop the subject off, we're done with it: if (i != cases - has_default - 1) { @@ -6101,6 +6108,14 @@ compiler_match(struct compiler *c, stmt_ty s) VISIT_SEQ(c, stmt, m->body); ADDOP_JUMP(c, JUMP_FORWARD, end); compiler_use_next_block(c, next); + if (pc.stores) { + Py_ssize_t i = PyList_GET_SIZE(pc.stores); + while (i--) { + ADDOP(c, POP_TOP); + } + Py_CLEAR(pc.stores); + } + compiler_use_next_block(c, fail_guard); } if (has_default) { if (cases == 1) { From dd8070aff5a0997611401c4710fca3ce97bbe377 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 1 Apr 2021 16:51:59 -0700 Subject: [PATCH 03/47] Fix or-patterns. --- Python/compile.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 8901d6343bc1aa..5aeba54b6c75f1 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5641,7 +5641,7 @@ static int compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) { assert(p->kind == MatchAs_kind); - basicblock *end, *fail_pop_1; + basicblock *end; RETURN_IF_FALSE(end = compiler_new_block(c)); // Need to make a copy for (possibly) storing later: ADDOP(c, DUP_TOP); @@ -5871,10 +5871,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) if (pc->stores == NULL || // Only copy the subject if we're *not* on the last alternative: (!is_last && !compiler_addop(c, DUP_TOP)) || - !compiler_pattern(c, alt, pc) || - // Only jump if we're *not* on the last alternative: - (!is_last && !compiler_addop_j(c, POP_JUMP_IF_TRUE, pass_pop_1)) || - !compiler_next_block(c)) + !compiler_pattern(c, alt, pc)) { goto fail; } @@ -5882,6 +5879,11 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // If this is the first alternative, save its stores as a "control" // for the others (they can't bind a different set of names): control = pc->stores; + if ((!is_last && !compiler_addop_j(c, POP_JUMP_IF_TRUE, pass_pop_1)) || + !compiler_next_block(c)) + { + goto fail; + } continue; } if (PyList_GET_SIZE(pc->stores) != PyList_GET_SIZE(control)) { @@ -5889,6 +5891,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) } if (PyList_GET_SIZE(stores_init) < PyList_GET_SIZE(pc->stores)) { + ADDOP_I(c, ROTATE, PyList_GET_SIZE(pc->stores) - PyList_GET_SIZE(stores_init) + 1); // Otherwise, check to see if we differ from the control list: Py_ssize_t j, k; for (j = PyList_GET_SIZE(stores_init); j < PyList_GET_SIZE(control); @@ -5901,10 +5904,16 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) } assert(j <= k); while (k++ < PyList_GET_SIZE(control)) { - // ADDOP_I(c, ROTATE, PyList_GET_SIZE(control) - j) + ADDOP_I(c, ROTATE, PyList_GET_SIZE(control) - j); } } } + // Only jump if we're *not* on the last alternative: + if ((!is_last && !compiler_addop_j(c, POP_JUMP_IF_TRUE, pass_pop_1)) || + !compiler_next_block(c)) + { + goto fail; + } Py_DECREF(pc->stores); } Py_XDECREF(stores_init); From 6a602e062ce6c8cdcd5654a561c75daadecb0e53 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 1 Apr 2021 22:34:57 -0700 Subject: [PATCH 04/47] Get or patterns working again. --- Python/compile.c | 119 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 84 insertions(+), 35 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 5aeba54b6c75f1..bbeab37b35fa8a 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -205,6 +205,9 @@ struct compiler { typedef struct { PyObject *stores; int allow_irrefutable; + basicblock **fail_pop; + Py_ssize_t fail_pop_size; + Py_ssize_t pop_on_fail; Py_ssize_t underneath; } pattern_context; @@ -5481,6 +5484,43 @@ compiler_slice(struct compiler *c, expr_ty s) _PyUnicode_EqualToASCIIString((N)->v.Name.id, "_")) +static int +pattern_helper_ensure_fail_pop(struct compiler *c, pattern_context *pc, + Py_ssize_t n) +{ + n++; + if (pc->fail_pop == NULL) { + pc->fail_pop = PyObject_Malloc(sizeof(basicblock*) * n); + } + else if (pc->fail_pop_size < n) { + pc->fail_pop = PyObject_Realloc(pc->fail_pop, + sizeof(basicblock*) * n); + } + RETURN_IF_FALSE(pc->fail_pop); + while (pc->fail_pop_size < n) { + pc->fail_pop[pc->fail_pop_size] = compiler_new_block(c); + RETURN_IF_FALSE(pc->fail_pop[pc->fail_pop_size++]) + } + return 1; +} + + +static int +pattern_helper_fail_pop_cleanup(struct compiler *c, pattern_context *pc) +{ + if (!pc->fail_pop_size) { + return 1; + } + while (--pc->fail_pop_size) { + compiler_use_next_block(c, pc->fail_pop[pc->fail_pop_size]); + ADDOP(c, POP_TOP); + } + compiler_use_next_block(c, pc->fail_pop[0]); + PyObject_Free(pc->fail_pop); + return 1; +} + + static int pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) { @@ -5503,7 +5543,6 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) if (pc->underneath) { ADDOP_I(c, ROTATE, pc->underneath + 1); } - // RETURN_IF_FALSE(compiler_nameop(c, n, Store)); return 1; } @@ -5532,6 +5571,7 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, goto error; } } + pc->pop_on_fail += size - 1; for (Py_ssize_t i = 0; i < size; i++) { expr_ty value = asdl_seq_GET(values, i); if (i == star) { @@ -5641,16 +5681,13 @@ static int compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) { assert(p->kind == MatchAs_kind); - basicblock *end; - RETURN_IF_FALSE(end = compiler_new_block(c)); // Need to make a copy for (possibly) storing later: ADDOP(c, DUP_TOP); + pc->pop_on_fail++; RETURN_IF_FALSE(compiler_pattern(c, p->v.MatchAs.pattern, pc)); - ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, end); + pc->pop_on_fail--; NEXT_BLOCK(c); RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.MatchAs.name, pc)); - ADDOP_LOAD_CONST(c, Py_True); - compiler_use_next_block(c, end); return 1; } @@ -5667,7 +5704,6 @@ compiler_pattern_capture(struct compiler *c, expr_ty p, pattern_context *pc) return compiler_error(c, e, p->v.Name.id); } RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.Name.id, pc)); - ADDOP_LOAD_CONST(c, Py_True); return 1; } @@ -5743,6 +5779,9 @@ compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) // Literal True, False, and None are compared by identity. All others use // equality: ADDOP_COMPARE(c, (v == Py_None || PyBool_Check(v)) ? Is : Eq); + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + NEXT_BLOCK(c); return 1; } @@ -5851,22 +5890,29 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // the others bind the same names (they should), then this becomes // pc->stores. PyObject *control = NULL; - basicblock *end, *pass_pop_1; + basicblock *end; RETURN_IF_FALSE(end = compiler_new_block(c)); - RETURN_IF_FALSE(pass_pop_1 = compiler_new_block(c)); Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns); assert(size > 1); // We're going to be messing with pc. Keep the original info handy: PyObject *stores_init; RETURN_IF_FALSE(stores_init = pc->stores ? pc->stores : PyList_New(0)); int allow_irrefutable = pc->allow_irrefutable; + basicblock **fail_pop = pc->fail_pop; + Py_ssize_t fail_pop_size = pc->fail_pop_size; + Py_ssize_t pop_on_fail = pc->pop_on_fail; + Py_ssize_t underneath = pc->underneath; for (Py_ssize_t i = 0; i < size; i++) { // NOTE: Can't use our nice returning macros here: they'll leak lists! expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); - pc->stores = PySequence_List(stores_init); // An irrefutable sub-pattern must be last, if it is allowed at all: int is_last = i == size - 1; + pc->stores = PySequence_List(stores_init); pc->allow_irrefutable = allow_irrefutable && is_last; + pc->fail_pop = NULL; + pc->fail_pop_size = 0; + pc->pop_on_fail = 0; + pc->underneath = is_last; SET_LOC(c, alt); if (pc->stores == NULL || // Only copy the subject if we're *not* on the last alternative: @@ -5879,11 +5925,13 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // If this is the first alternative, save its stores as a "control" // for the others (they can't bind a different set of names): control = pc->stores; - if ((!is_last && !compiler_addop_j(c, POP_JUMP_IF_TRUE, pass_pop_1)) || + ADDOP(c, POP_TOP); + if (!compiler_addop_j(c, JUMP_FORWARD, end) || !compiler_next_block(c)) { goto fail; } + pattern_helper_fail_pop_cleanup(c, pc); continue; } if (PyList_GET_SIZE(pc->stores) != PyList_GET_SIZE(control)) { @@ -5908,22 +5956,27 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) } } } - // Only jump if we're *not* on the last alternative: - if ((!is_last && !compiler_addop_j(c, POP_JUMP_IF_TRUE, pass_pop_1)) || - !compiler_next_block(c)) + Py_DECREF(pc->stores); + if (!is_last) { + ADDOP(c, POP_TOP); + } + if (!compiler_addop_j(c, JUMP_FORWARD, end) || + !compiler_next_block(c)) { goto fail; } - Py_DECREF(pc->stores); + pattern_helper_fail_pop_cleanup(c, pc); } Py_XDECREF(stores_init); // Update pc->stores and restore pc->allow_irrefutable: pc->stores = control; pc->allow_irrefutable = allow_irrefutable; - ADDOP_JUMP(c, JUMP_FORWARD, end); - compiler_use_next_block(c, pass_pop_1); - ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_True); + pc->fail_pop = fail_pop; + pc->fail_pop_size = fail_pop_size; + pc->pop_on_fail = pop_on_fail; + pc->underneath = underneath; + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, JUMP_FORWARD, pc->fail_pop[pc->pop_on_fail]); compiler_use_next_block(c, end); return 1; diff: @@ -6008,6 +6061,9 @@ compiler_pattern_value(struct compiler *c, expr_ty p, pattern_context *pc) assert(p->v.Attribute.ctx == Load); VISIT(c, expr, p); ADDOP_COMPARE(c, Eq); + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + NEXT_BLOCK(c); return 1; } @@ -6024,7 +6080,6 @@ compiler_pattern_wildcard(struct compiler *c, expr_ty p, pattern_context *pc) return compiler_error(c, e); } ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_True); return 1; } @@ -6070,7 +6125,7 @@ static int compiler_match(struct compiler *c, stmt_ty s) { VISIT(c, expr, s->v.Match.subject); - basicblock *next, *fail_guard, *end; + basicblock *end; RETURN_IF_FALSE(end = compiler_new_block(c)); Py_ssize_t cases = asdl_seq_LEN(s->v.Match.cases); assert(cases); @@ -6085,20 +6140,20 @@ compiler_match(struct compiler *c, stmt_ty s) for (Py_ssize_t i = 0; i < cases - has_default; i++) { m = asdl_seq_GET(s->v.Match.cases, i); SET_LOC(c, m->pattern); - RETURN_IF_FALSE(next = compiler_new_block(c)); - RETURN_IF_FALSE(fail_guard = compiler_new_block(c)); // If pc.allow_irrefutable is 0, any name captures against our subject // will raise. Irrefutable cases must be either guarded, last, or both: pc.allow_irrefutable = m->guard != NULL || i == cases - 1; + pc.fail_pop = NULL; + pc.fail_pop_size = 0; + pc.pop_on_fail = 0; pc.underneath = 0; // Only copy the subject if we're *not* on the last case: if (i != cases - has_default - 1) { ADDOP(c, DUP_TOP); } int result = compiler_pattern(c, m->pattern, &pc); - assert(!pc.underneath); RETURN_IF_FALSE(result); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, next); + assert(!pc.underneath); NEXT_BLOCK(c); if (pc.stores) { Py_ssize_t i = PyList_GET_SIZE(pc.stores); @@ -6106,9 +6161,11 @@ compiler_match(struct compiler *c, stmt_ty s) PyObject *n = PyList_GET_ITEM(pc.stores, i); RETURN_IF_FALSE(compiler_nameop(c, n, Store)); } + Py_CLEAR(pc.stores); } if (m->guard) { - RETURN_IF_FALSE(compiler_jump_if(c, m->guard, fail_guard, 0)); + RETURN_IF_FALSE(pattern_helper_ensure_fail_pop(c, &pc, 0)); + RETURN_IF_FALSE(compiler_jump_if(c, m->guard, pc.fail_pop[0], 0)); } // Success! Pop the subject off, we're done with it: if (i != cases - has_default - 1) { @@ -6116,15 +6173,7 @@ compiler_match(struct compiler *c, stmt_ty s) } VISIT_SEQ(c, stmt, m->body); ADDOP_JUMP(c, JUMP_FORWARD, end); - compiler_use_next_block(c, next); - if (pc.stores) { - Py_ssize_t i = PyList_GET_SIZE(pc.stores); - while (i--) { - ADDOP(c, POP_TOP); - } - Py_CLEAR(pc.stores); - } - compiler_use_next_block(c, fail_guard); + pattern_helper_fail_pop_cleanup(c, &pc); } if (has_default) { if (cases == 1) { From 96b73e1e220ce1e56417ce281a13390f909d93c4 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 1 Apr 2021 22:49:16 -0700 Subject: [PATCH 05/47] Get basic mapping patterns working. --- Python/compile.c | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index bbeab37b35fa8a..915d167afbefd2 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5789,27 +5789,20 @@ compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) static int compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) { - basicblock *end, *fail_pop_1, *fail_pop_3; - RETURN_IF_FALSE(end = compiler_new_block(c)); - RETURN_IF_FALSE(fail_pop_1 = compiler_new_block(c)); - RETURN_IF_FALSE(fail_pop_3 = compiler_new_block(c)); asdl_expr_seq *keys = p->v.Dict.keys; asdl_expr_seq *values = p->v.Dict.values; Py_ssize_t size = asdl_seq_LEN(values); // A starred pattern will be a keyless value. It is guaranteed to be last: int star = size ? !asdl_seq_GET(keys, size - 1) : 0; ADDOP(c, MATCH_MAPPING); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); + pc->pop_on_fail++; + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + pc->pop_on_fail--; NEXT_BLOCK(c); if (!size) { // If the pattern is just "{}", we're done! ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_True); - ADDOP_JUMP(c, JUMP_FORWARD, end); - compiler_use_next_block(c, fail_pop_1); - ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_False); - compiler_use_next_block(c, end); return 1; } if (size - star) { @@ -5817,7 +5810,10 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - star)); ADDOP_COMPARE(c, GtE); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); + pc->pop_on_fail++; + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + pc->pop_on_fail--; NEXT_BLOCK(c); } if (INT_MAX < size - star - 1) { @@ -5836,7 +5832,10 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) } ADDOP_I(c, BUILD_TUPLE, size - star); ADDOP(c, MATCH_KEYS); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_3); + pc->pop_on_fail += 3; + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + pc->pop_on_fail -= 3; NEXT_BLOCK(c); // So far so good. There's now a tuple of values on the stack to match // sub-patterns against: @@ -5848,9 +5847,9 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, DUP_TOP); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); + pc->pop_on_fail += 3; RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_3); - NEXT_BLOCK(c); + pc->pop_on_fail -= 3; } // If we get this far, it's a match! We're done with that tuple of values. ADDOP(c, POP_TOP); @@ -5858,7 +5857,9 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) // If we had a starred name, bind a dict of remaining items to it: ADDOP(c, COPY_DICT_WITHOUT_KEYS); PyObject *id = asdl_seq_GET(values, size - 1)->v.Name.id; + pc->underneath++; RETURN_IF_FALSE(pattern_helper_store_name(c, id, pc)); + pc->underneath--; } else { // Otherwise, we don't care about this tuple of keys anymore: @@ -5866,18 +5867,6 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) } // Pop the subject: ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_True); - ADDOP_JUMP(c, JUMP_FORWARD, end); - // The top two items are a tuple of values or None, followed by a tuple of - // keys. Pop them both: - compiler_use_next_block(c, fail_pop_3); - ADDOP(c, POP_TOP); - ADDOP(c, POP_TOP); - compiler_use_next_block(c, fail_pop_1); - // Pop the subject: - ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_False); - compiler_use_next_block(c, end); return 1; } From ef3c4b4bba4a09e9173bbd692944d184253355c4 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 08:59:35 -0700 Subject: [PATCH 06/47] Get some sequences working. --- Python/compile.c | 97 +++++++++++------------------------------------- 1 file changed, 22 insertions(+), 75 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 915d167afbefd2..190408331c71ca 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5553,68 +5553,21 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, { RETURN_IF_FALSE(unpack_helper(c, values)); // We've now got a bunch of new subjects on the stack. If any of them fail - // to match, we need to pop everything else off, then finally push False. - // fails is an array of blocks that correspond to the necessary amount of - // popping for each element: - basicblock **fails; + // to match, we need to pop everything else off. Py_ssize_t size = asdl_seq_LEN(values); - fails = (basicblock **)PyObject_Malloc(sizeof(basicblock*) * size); - if (fails == NULL) { - PyErr_NoMemory(); - return 0; - } - // NOTE: Can't use our nice returning macros anymore: they'll leak memory! - // goto error on error. - for (Py_ssize_t i = 0; i < size; i++) { - fails[i] = compiler_new_block(c); - if (fails[i] == NULL) { - goto error; - } - } - pc->pop_on_fail += size - 1; + pc->pop_on_fail += size; + pc->underneath += size; for (Py_ssize_t i = 0; i < size; i++) { + pc->pop_on_fail--; + pc->underneath--; expr_ty value = asdl_seq_GET(values, i); if (i == star) { assert(value->kind == Starred_kind); value = value->v.Starred.value; } - if (!compiler_pattern_subpattern(c, value, pc) || - !compiler_addop_j(c, POP_JUMP_IF_FALSE, fails[i]) || - compiler_next_block(c) == NULL) - { - goto error; - } - } - // Success! - basicblock *end = compiler_new_block(c); - if (end == NULL || - !compiler_addop_load_const(c, Py_True) || - !compiler_addop_j(c, JUMP_FORWARD, end)) - { - goto error; - } - // This is where we handle failed sub-patterns. For a sequence pattern like - // [a, b, c, d], this will look like: - // fails[0]: POP_TOP - // fails[1]: POP_TOP - // fails[2]: POP_TOP - // fails[3]: LOAD_CONST False - for (Py_ssize_t i = 0; i < size - 1; i++) { - compiler_use_next_block(c, fails[i]); - if (!compiler_addop(c, POP_TOP)) { - goto error; - } - } - compiler_use_next_block(c, fails[size - 1]); - if (!compiler_addop_load_const(c, Py_False)) { - goto error; + RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); } - compiler_use_next_block(c, end); - PyObject_Free(fails); return 1; -error: - PyObject_Free(fails); - return 0; } // Like pattern_helper_sequence_unpack, but uses BINARY_SUBSCR instead of @@ -5624,9 +5577,6 @@ static int pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, Py_ssize_t star, pattern_context *pc) { - basicblock *end, *fail_pop_1; - RETURN_IF_FALSE(end = compiler_new_block(c)); - RETURN_IF_FALSE(fail_pop_1 = compiler_new_block(c)); Py_ssize_t size = asdl_seq_LEN(values); for (Py_ssize_t i = 0; i < size; i++) { expr_ty value = asdl_seq_GET(values, i); @@ -5650,17 +5600,14 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, ADDOP(c, BINARY_SUBTRACT); } ADDOP(c, BINARY_SUBSCR); + pc->pop_on_fail++; + pc->underneath++; RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); + pc->pop_on_fail--; + pc->underneath--; NEXT_BLOCK(c); } ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_True); - ADDOP_JUMP(c, JUMP_FORWARD, end); - compiler_use_next_block(c, fail_pop_1); - ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_False); - compiler_use_next_block(c, end); return 1; } @@ -6001,18 +5948,21 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) } only_wildcard &= WILDCARD_CHECK(value); } - basicblock *end, *fail_pop_1; - RETURN_IF_FALSE(end = compiler_new_block(c)); - RETURN_IF_FALSE(fail_pop_1 = compiler_new_block(c)); ADDOP(c, MATCH_SEQUENCE); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); + pc->pop_on_fail++; + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + pc->pop_on_fail--; NEXT_BLOCK(c); if (star < 0) { // No star: len(subject) == size ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size)); ADDOP_COMPARE(c, Eq); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); + pc->pop_on_fail++; + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + pc->pop_on_fail--; NEXT_BLOCK(c); } else if (size > 1) { @@ -6020,13 +5970,15 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - 1)); ADDOP_COMPARE(c, GtE); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); + pc->pop_on_fail++; + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + pc->pop_on_fail--; NEXT_BLOCK(c); } if (only_wildcard) { // Patterns like: [] / [_] / [_, _] / [*_] / [_, *_] / [_, _, *_] / etc. ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_True); } else if (star_wildcard) { RETURN_IF_FALSE(pattern_helper_sequence_subscr(c, values, star, pc)); @@ -6034,11 +5986,6 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) else { RETURN_IF_FALSE(pattern_helper_sequence_unpack(c, values, star, pc)); } - ADDOP_JUMP(c, JUMP_FORWARD, end); - compiler_use_next_block(c, fail_pop_1); - ADDOP(c, POP_TOP) - ADDOP_LOAD_CONST(c, Py_False); - compiler_use_next_block(c, end); return 1; } From c2c10075739383c8f53f14444f3704bb938d039f Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 09:16:13 -0700 Subject: [PATCH 07/47] Fix issue with name stores in subpatterns. --- Python/compile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/compile.c b/Python/compile.c index 190408331c71ca..a053eec99dbb93 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5543,6 +5543,7 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) if (pc->underneath) { ADDOP_I(c, ROTATE, pc->underneath + 1); } + pc->pop_on_fail++; return 1; } From 87472c0200c47c71dc2e92842615bd5365e9b828 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 09:21:00 -0700 Subject: [PATCH 08/47] Get everything except class patterns working. --- Python/compile.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Python/compile.c b/Python/compile.c index a053eec99dbb93..8329ec71b67255 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5632,8 +5632,10 @@ compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) // Need to make a copy for (possibly) storing later: ADDOP(c, DUP_TOP); pc->pop_on_fail++; + pc->underneath++; RETURN_IF_FALSE(compiler_pattern(c, p->v.MatchAs.pattern, pc)); pc->pop_on_fail--; + pc->underneath--; NEXT_BLOCK(c); RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.MatchAs.name, pc)); return 1; @@ -5796,8 +5798,10 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); pc->pop_on_fail += 3; + pc->underneath += 3; RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); pc->pop_on_fail -= 3; + pc->underneath -= 3; } // If we get this far, it's a match! We're done with that tuple of values. ADDOP(c, POP_TOP); From 2f4f30133c9bf34d54d6dc0c20435af01a5f591a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 09:26:31 -0700 Subject: [PATCH 09/47] Get class patterns working (all tests pass now)! --- Python/compile.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 8329ec71b67255..e8ce57f5e91e2e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5670,9 +5670,6 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) return compiler_error(c, e, p->v.Call.func); } RETURN_IF_FALSE(!validate_keywords(c, kwargs)); - basicblock *end, *fail_pop_1; - RETURN_IF_FALSE(end = compiler_new_block(c)); - RETURN_IF_FALSE(fail_pop_1 = compiler_new_block(c)); VISIT(c, expr, p->v.Call.func); PyObject *kwnames; RETURN_IF_FALSE(kwnames = PyTuple_New(nkwargs)); @@ -5684,7 +5681,10 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) } ADDOP_LOAD_CONST_NEW(c, kwnames); ADDOP_I(c, MATCH_CLASS, nargs); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); + pc->pop_on_fail++; + pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); + ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + pc->pop_on_fail--; NEXT_BLOCK(c); // TOS is now a tuple of (nargs + nkwargs) attributes. for (i = 0; i < nargs + nkwargs; i++) { @@ -5704,18 +5704,15 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, DUP_TOP); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); + pc->pop_on_fail++; + pc->underneath++; RETURN_IF_FALSE(compiler_pattern_subpattern(c, arg, pc)); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, fail_pop_1); + pc->pop_on_fail--; + pc->underneath--; NEXT_BLOCK(c); } // Success! Pop the tuple of attributes: ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_True); - ADDOP_JUMP(c, JUMP_FORWARD, end); - compiler_use_next_block(c, fail_pop_1); - ADDOP(c, POP_TOP); - ADDOP_LOAD_CONST(c, Py_False); - compiler_use_next_block(c, end); return 1; } From e9e9e7b31375d3cfaceff002d42a4f68b138391a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 11:50:03 -0700 Subject: [PATCH 10/47] Successfully untangle names in alternatives. --- Lib/test/test_patma.py | 24 +++++++++ Python/compile.c | 114 ++++++++++++++++++++--------------------- 2 files changed, 80 insertions(+), 58 deletions(-) diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index 286b190adcf3d8..7b7d13df288662 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2841,6 +2841,30 @@ def test_patma_281(self): self.assertEqual(x, range(10)) self.assertIs(y, None) + def test_patma_282(self): + def f(x): + match x: + case ((a, b, c, d, e, f, g, h, i, 9) | + (h, g, i, a, b, d, e, c, f, 10) | + (g, b, a, c, d, -5, e, h, i, f) | + (-1, d, f, b, g, e, i, a, h, c)): + pass + out = locals() + del out["x"] + return out + alts = [ + dict(a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7, i=8), + dict(h=1, g=2, i=3, a=4, b=5, d=6, e=7, c=8, f=9), + dict(g=0, b=-1, a=-2, c=-3, d=-4, e=-6, h=-7, i=-8, f=-9), + dict(d=-2, f=-3, b=-4, g=-5, e=-6, i=-7, a=-8, h=-9, c=-10), + dict(), + ] + self.assertEqual(f(range(10)), alts[0]) + self.assertEqual(f(range(1, 11)), alts[1]) + self.assertEqual(f(range(0, -10, -1)), alts[2]) + self.assertEqual(f(range(-1, -11, -1)), alts[3]) + self.assertEqual(f(range(10, 20)), alts[4]) + class PerfPatma(TestPatma): diff --git a/Python/compile.c b/Python/compile.c index e8ce57f5e91e2e..7ab713903e9481 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5472,11 +5472,12 @@ compiler_slice(struct compiler *c, expr_ty s) // PEP 634: Structural Pattern Matching -// To keep things simple, all compiler_pattern_* routines follow the convention -// of replacing TOS (the subject for the given pattern) with either True (match) -// or False (no match). We do this even for irrefutable patterns; the idea is -// that it's much easier to smooth out any redundant pushing, popping, and -// jumping in the peephole optimizer than to detect or predict it here. +// TODO: this comment +// TODO: other comments +// TODO: ROTATE perf tests +// TODO: POP op? perf tests +// TODO: check for memory leaks +// TODO: variants of test_patma_282 with mappings, classes, stars, stores before/after #define WILDCARD_CHECK(N) \ @@ -5488,23 +5489,33 @@ static int pattern_helper_ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n) { - n++; + Py_ssize_t size = n + 1; if (pc->fail_pop == NULL) { - pc->fail_pop = PyObject_Malloc(sizeof(basicblock*) * n); + pc->fail_pop = PyObject_Malloc(sizeof(basicblock*) * size); } - else if (pc->fail_pop_size < n) { + else if (pc->fail_pop_size < size) { pc->fail_pop = PyObject_Realloc(pc->fail_pop, - sizeof(basicblock*) * n); + sizeof(basicblock*) * size); } RETURN_IF_FALSE(pc->fail_pop); - while (pc->fail_pop_size < n) { + while (pc->fail_pop_size < size) { pc->fail_pop[pc->fail_pop_size] = compiler_new_block(c); - RETURN_IF_FALSE(pc->fail_pop[pc->fail_pop_size++]) + RETURN_IF_FALSE(pc->fail_pop[pc->fail_pop_size++]); } return 1; } +static int +pattern_helper_jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) +{ + RETURN_IF_FALSE(pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail)); + ADDOP_JUMP(c, op, pc->fail_pop[pc->pop_on_fail]); + NEXT_BLOCK(c); + return 1; +} + + static int pattern_helper_fail_pop_cleanup(struct compiler *c, pattern_context *pc) { @@ -5682,10 +5693,8 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, kwnames); ADDOP_I(c, MATCH_CLASS, nargs); pc->pop_on_fail++; - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; - NEXT_BLOCK(c); // TOS is now a tuple of (nargs + nkwargs) attributes. for (i = 0; i < nargs + nkwargs; i++) { expr_ty arg; @@ -5726,8 +5735,7 @@ compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) // Literal True, False, and None are compared by identity. All others use // equality: ADDOP_COMPARE(c, (v == Py_None || PyBool_Check(v)) ? Is : Eq); - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); NEXT_BLOCK(c); return 1; } @@ -5743,10 +5751,8 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) int star = size ? !asdl_seq_GET(keys, size - 1) : 0; ADDOP(c, MATCH_MAPPING); pc->pop_on_fail++; - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; - NEXT_BLOCK(c); if (!size) { // If the pattern is just "{}", we're done! ADDOP(c, POP_TOP); @@ -5758,10 +5764,8 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - star)); ADDOP_COMPARE(c, GtE); pc->pop_on_fail++; - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; - NEXT_BLOCK(c); } if (INT_MAX < size - star - 1) { return compiler_error(c, "too many sub-patterns in mapping pattern"); @@ -5780,10 +5784,8 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_I(c, BUILD_TUPLE, size - star); ADDOP(c, MATCH_KEYS); pc->pop_on_fail += 3; - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail -= 3; - NEXT_BLOCK(c); // So far so good. There's now a tuple of values on the stack to match // sub-patterns against: for (Py_ssize_t i = 0; i < size - star; i++) { @@ -5850,7 +5852,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->pop_on_fail = 0; - pc->underneath = is_last; + pc->underneath = 0; SET_LOC(c, alt); if (pc->stores == NULL || // Only copy the subject if we're *not* on the last alternative: @@ -5859,29 +5861,32 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) { goto fail; } + if (!is_last) { + // TODO: UNROTATE + Py_ssize_t nstores = PyList_GET_SIZE(pc->stores) - PyList_GET_SIZE(stores_init); + for (Py_ssize_t i = 0; i < nstores; i++) { + if (!compiler_addop_i(c, ROTATE, nstores + 1)) { + goto fail; + } + } + if (!compiler_addop(c, POP_TOP)) { + goto fail; + } + } if (!i) { // If this is the first alternative, save its stores as a "control" // for the others (they can't bind a different set of names): control = pc->stores; - ADDOP(c, POP_TOP); - if (!compiler_addop_j(c, JUMP_FORWARD, end) || - !compiler_next_block(c)) - { - goto fail; - } - pattern_helper_fail_pop_cleanup(c, pc); - continue; + Py_INCREF(control); } - if (PyList_GET_SIZE(pc->stores) != PyList_GET_SIZE(control)) { + else if (PyList_GET_SIZE(pc->stores) != PyList_GET_SIZE(control)) { goto diff; } - if (PyList_GET_SIZE(stores_init) < PyList_GET_SIZE(pc->stores)) - { - ADDOP_I(c, ROTATE, PyList_GET_SIZE(pc->stores) - PyList_GET_SIZE(stores_init) + 1); + else if (PyList_GET_SIZE(stores_init) < PyList_GET_SIZE(pc->stores)) { // Otherwise, check to see if we differ from the control list: Py_ssize_t j, k; for (j = PyList_GET_SIZE(stores_init); j < PyList_GET_SIZE(control); - j++) + j++) { k = PySequence_Index(pc->stores, PyList_GET_ITEM(control, j)); if (k < 0) { @@ -5889,21 +5894,23 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) goto diff; } assert(j <= k); + // This is a really ineffiecient way of reordering the on the + // stack to match the order of control... but it works! while (k++ < PyList_GET_SIZE(control)) { ADDOP_I(c, ROTATE, PyList_GET_SIZE(control) - j); + PyList_Insert(pc->stores, j, + PySequence_GetItem(pc->stores, -1)); + PySequence_DelItem(pc->stores, -1); } } } Py_DECREF(pc->stores); - if (!is_last) { - ADDOP(c, POP_TOP); - } if (!compiler_addop_j(c, JUMP_FORWARD, end) || - !compiler_next_block(c)) + !compiler_next_block(c) || + !pattern_helper_fail_pop_cleanup(c, pc)) { goto fail; } - pattern_helper_fail_pop_cleanup(c, pc); } Py_XDECREF(stores_init); // Update pc->stores and restore pc->allow_irrefutable: @@ -5913,8 +5920,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) pc->fail_pop_size = fail_pop_size; pc->pop_on_fail = pop_on_fail; pc->underneath = underneath; - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, JUMP_FORWARD, pc->fail_pop[pc->pop_on_fail]); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, JUMP_FORWARD)); compiler_use_next_block(c, end); return 1; diff: @@ -5952,20 +5958,16 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) } ADDOP(c, MATCH_SEQUENCE); pc->pop_on_fail++; - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; - NEXT_BLOCK(c); if (star < 0) { // No star: len(subject) == size ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size)); ADDOP_COMPARE(c, Eq); pc->pop_on_fail++; - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; - NEXT_BLOCK(c); } else if (size > 1) { // Star: len(subject) >= size - 1 @@ -5973,10 +5975,8 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - 1)); ADDOP_COMPARE(c, GtE); pc->pop_on_fail++; - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; - NEXT_BLOCK(c); } if (only_wildcard) { // Patterns like: [] / [_] / [_, _] / [*_] / [_, *_] / [_, _, *_] / etc. @@ -5999,9 +5999,7 @@ compiler_pattern_value(struct compiler *c, expr_ty p, pattern_context *pc) assert(p->v.Attribute.ctx == Load); VISIT(c, expr, p); ADDOP_COMPARE(c, Eq); - pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail); - ADDOP_JUMP(c, POP_JUMP_IF_FALSE, pc->fail_pop[pc->pop_on_fail]); - NEXT_BLOCK(c); + RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); return 1; } From fa05706d236aff3f21e0f2aa1fd16db138aec165 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 12:55:26 -0700 Subject: [PATCH 11/47] Update benchmark command --- Lib/test/test_patma.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index 7b7d13df288662..5b5c2494133021 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2896,7 +2896,8 @@ def setUpClass(): """ -sudo ./python -m pyperf system tune && \ - ./python -m pyperf timeit --rigorous --setup "from test.test_patma import PerfPatma; p = PerfPatma()" "p.run_perf()"; \ -sudo ./python -m pyperf system reset +# From inside venv pointing to this Python, with pyperf installed: +sudo $(which python) -m pyperf system tune && \ + $(which python) -m pyperf timeit --rigorous --setup "from test.test_patma import PerfPatma; p = PerfPatma()" "p.run_perf()"; \ +sudo $(which python) -m pyperf system reset """ From 3e29a0e44e6acd128c4348e7aa562c9eddbb5c0a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 21:49:59 -0700 Subject: [PATCH 12/47] Remove old comment. --- Python/ceval.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index f129d992834ae5..76e5c2aae88847 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4414,9 +4414,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) PyObject *top = TOP(); memmove(&PEEK(oparg - 1), &PEEK(oparg), sizeof(PyObject*) * (oparg - 1)); - // for (int i = 1; i < oparg; i++) { - // PEEK(i) = PEEK(i + 1); - // } PEEK(oparg) = top; DISPATCH(); } From c5fd080bc9c68b05f47b727c8bcac921b70be58e Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 22:25:42 -0700 Subject: [PATCH 13/47] Add comments and handling for memory errors --- Python/compile.c | 115 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 85 insertions(+), 30 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 75b9f58b78499e..0517952e42d4bd 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -203,12 +203,28 @@ struct compiler { }; typedef struct { + // A list of strings corresponding to name captures. PyObject *stores; + // If 0, any name captures against our subject will raise. int allow_irrefutable; + // An array of blocks to jump to on failure. fail_pop[i] will pop i items + // off of the stack. The end result looks like this (with each block falling + // through to the next): + // fail_pop[4]: POP_TOP + // fail_pop[3]: POP_TOP + // fail_pop[2]: POP_TOP + // fail_pop[1]: POP_TOP + // fail_pop[0]: NOP basicblock **fail_pop; + // The current length of fail_pop. Py_ssize_t fail_pop_size; + // How many items should be popped on failure, since subpatterns often need + // to clean up for their parents. Typical usage looks like: + // ADDOP_JUMP(c, JUMP_ABSOLUTE, pc->fail_pop[pc->pop_on_fail]); Py_ssize_t pop_on_fail; - Py_ssize_t underneath; + // The number of items on top of the stack that need to *stay* on top of the + // stack. Variable captures go beneath these. + Py_ssize_t on_top; } pattern_context; static int compiler_enter_scope(struct compiler *, identifier, int, void *, int); @@ -5472,6 +5488,8 @@ compiler_slice(struct compiler *c, expr_ty s) // PEP 634: Structural Pattern Matching +// To keep things simple, all compiler_pattern_* routines + // TODO: this comment // TODO: other comments // TODO: ROTATE perf tests @@ -5485,6 +5503,7 @@ compiler_slice(struct compiler *c, expr_ty s) _PyUnicode_EqualToASCIIString((N)->v.Name.id, "_")) +// Allocate or resize pc->fail_pop to allow for n items to be popped on failure. static int pattern_helper_ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n) @@ -5492,12 +5511,20 @@ pattern_helper_ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t size = n + 1; if (pc->fail_pop == NULL) { pc->fail_pop = PyObject_Malloc(sizeof(basicblock*) * size); + if (pc->fail_pop == NULL) { + PyErr_NoMemory(); + return 0; + } } else if (pc->fail_pop_size < size) { - pc->fail_pop = PyObject_Realloc(pc->fail_pop, - sizeof(basicblock*) * size); + Py_ssize_t needed = sizeof(basicblock*) * size; + basicblock **new = PyObject_Realloc(pc->fail_pop, needed); + if (new == NULL) { + PyErr_NoMemory(); + return 0; + } + pc->fail_pop = new; } - RETURN_IF_FALSE(pc->fail_pop); while (pc->fail_pop_size < size) { pc->fail_pop[pc->fail_pop_size] = compiler_new_block(c); RETURN_IF_FALSE(pc->fail_pop[pc->fail_pop_size++]); @@ -5506,6 +5533,7 @@ pattern_helper_ensure_fail_pop(struct compiler *c, pattern_context *pc, } +// Use op to jump to the correct fail_pop block. static int pattern_helper_jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) { @@ -5516,18 +5544,26 @@ pattern_helper_jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) } +// Build all of the fail_pop blocks and free fail_pop. static int pattern_helper_fail_pop_cleanup(struct compiler *c, pattern_context *pc) { if (!pc->fail_pop_size) { - return 1; + goto done; } while (--pc->fail_pop_size) { compiler_use_next_block(c, pc->fail_pop[pc->fail_pop_size]); - ADDOP(c, POP_TOP); + if (!compiler_addop(c, POP_TOP)) { + PyObject_Free(pc->fail_pop); + pc->fail_pop_size = 0; + pc->fail_pop = NULL; + return 0; + } } compiler_use_next_block(c, pc->fail_pop[0]); +done: PyObject_Free(pc->fail_pop); + pc->fail_pop = NULL; return 1; } @@ -5551,10 +5587,12 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) } } RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); - if (pc->underneath) { - ADDOP_I(c, ROTATE, pc->underneath + 1); - } + // This object will be stored on success, but needs to be popped on failure: pc->pop_on_fail++; + if (pc->on_top) { + // Rotate this object underneath any items we need to preserve: + ADDOP_I(c, ROTATE, pc->on_top + 1); + } return 1; } @@ -5564,14 +5602,16 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, Py_ssize_t star, pattern_context *pc) { RETURN_IF_FALSE(unpack_helper(c, values)); - // We've now got a bunch of new subjects on the stack. If any of them fail - // to match, we need to pop everything else off. Py_ssize_t size = asdl_seq_LEN(values); + // We've now got a bunch of new subjects on the stack. If any of them fail + // to match, we need to pop everything else off: pc->pop_on_fail += size; - pc->underneath += size; + // They need to remain on top of the stack after each subpattern match: + pc->on_top += size; for (Py_ssize_t i = 0; i < size; i++) { + // One less item to keep track of each time we loop through: pc->pop_on_fail--; - pc->underneath--; + pc->on_top--; expr_ty value = asdl_seq_GET(values, i); if (i == star) { assert(value->kind == Starred_kind); @@ -5613,10 +5653,10 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, } ADDOP(c, BINARY_SUBSCR); pc->pop_on_fail++; - pc->underneath++; + pc->on_top++; RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); pc->pop_on_fail--; - pc->underneath--; + pc->on_top--; NEXT_BLOCK(c); } ADDOP(c, POP_TOP); @@ -5643,10 +5683,10 @@ compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) // Need to make a copy for (possibly) storing later: ADDOP(c, DUP_TOP); pc->pop_on_fail++; - pc->underneath++; + pc->on_top++; RETURN_IF_FALSE(compiler_pattern(c, p->v.MatchAs.pattern, pc)); pc->pop_on_fail--; - pc->underneath--; + pc->on_top--; NEXT_BLOCK(c); RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.MatchAs.name, pc)); return 1; @@ -5693,8 +5733,10 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, kwnames); ADDOP_I(c, MATCH_CLASS, nargs); pc->pop_on_fail++; + pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; + pc->on_top--; // TOS is now a tuple of (nargs + nkwargs) attributes. for (i = 0; i < nargs + nkwargs; i++) { expr_ty arg; @@ -5714,10 +5756,10 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); pc->pop_on_fail++; - pc->underneath++; + pc->on_top++; RETURN_IF_FALSE(compiler_pattern_subpattern(c, arg, pc)); pc->pop_on_fail--; - pc->underneath--; + pc->on_top--; NEXT_BLOCK(c); } // Success! Pop the tuple of attributes: @@ -5751,8 +5793,10 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) int star = size ? !asdl_seq_GET(keys, size - 1) : 0; ADDOP(c, MATCH_MAPPING); pc->pop_on_fail++; + pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; + pc->on_top--; if (!size) { // If the pattern is just "{}", we're done! ADDOP(c, POP_TOP); @@ -5764,8 +5808,10 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - star)); ADDOP_COMPARE(c, GtE); pc->pop_on_fail++; + pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; + pc->on_top--; } if (INT_MAX < size - star - 1) { return compiler_error(c, "too many sub-patterns in mapping pattern"); @@ -5784,8 +5830,10 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_I(c, BUILD_TUPLE, size - star); ADDOP(c, MATCH_KEYS); pc->pop_on_fail += 3; + pc->on_top+=3; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail -= 3; + pc->on_top-=3; // So far so good. There's now a tuple of values on the stack to match // sub-patterns against: for (Py_ssize_t i = 0; i < size - star; i++) { @@ -5797,10 +5845,10 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); pc->pop_on_fail += 3; - pc->underneath += 3; + pc->on_top += 3; RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); pc->pop_on_fail -= 3; - pc->underneath -= 3; + pc->on_top -= 3; } // If we get this far, it's a match! We're done with that tuple of values. ADDOP(c, POP_TOP); @@ -5808,9 +5856,11 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) // If we had a starred name, bind a dict of remaining items to it: ADDOP(c, COPY_DICT_WITHOUT_KEYS); PyObject *id = asdl_seq_GET(values, size - 1)->v.Name.id; - pc->underneath++; + pc->pop_on_fail++; + pc->on_top++; RETURN_IF_FALSE(pattern_helper_store_name(c, id, pc)); - pc->underneath--; + pc->pop_on_fail--; + pc->on_top--; } else { // Otherwise, we don't care about this tuple of keys anymore: @@ -5841,7 +5891,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) basicblock **fail_pop = pc->fail_pop; Py_ssize_t fail_pop_size = pc->fail_pop_size; Py_ssize_t pop_on_fail = pc->pop_on_fail; - Py_ssize_t underneath = pc->underneath; + Py_ssize_t on_top = pc->on_top; for (Py_ssize_t i = 0; i < size; i++) { // NOTE: Can't use our nice returning macros here: they'll leak lists! expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); @@ -5852,7 +5902,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->pop_on_fail = 0; - pc->underneath = 0; + pc->on_top = 0; SET_LOC(c, alt); if (pc->stores == NULL || // Only copy the subject if we're *not* on the last alternative: @@ -5923,7 +5973,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) pc->fail_pop = fail_pop; pc->fail_pop_size = fail_pop_size; pc->pop_on_fail = pop_on_fail; - pc->underneath = underneath; + pc->on_top = on_top; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, JUMP_FORWARD)); compiler_use_next_block(c, end); return 1; @@ -5962,16 +6012,20 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) } ADDOP(c, MATCH_SEQUENCE); pc->pop_on_fail++; + pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; + pc->on_top--; if (star < 0) { // No star: len(subject) == size ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size)); ADDOP_COMPARE(c, Eq); pc->pop_on_fail++; + pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; + pc->on_top--; } else if (size > 1) { // Star: len(subject) >= size - 1 @@ -5979,8 +6033,10 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - 1)); ADDOP_COMPARE(c, GtE); pc->pop_on_fail++; + pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->pop_on_fail--; + pc->on_top--; } if (only_wildcard) { // Patterns like: [] / [_] / [_, _] / [*_] / [_, *_] / [_, _, *_] / etc. @@ -6080,20 +6136,19 @@ compiler_match(struct compiler *c, stmt_ty s) for (Py_ssize_t i = 0; i < cases - has_default; i++) { m = asdl_seq_GET(s->v.Match.cases, i); SET_LOC(c, m->pattern); - // If pc.allow_irrefutable is 0, any name captures against our subject - // will raise. Irrefutable cases must be either guarded, last, or both: + // Irrefutable cases must be either guarded, last, or both: pc.allow_irrefutable = m->guard != NULL || i == cases - 1; pc.fail_pop = NULL; pc.fail_pop_size = 0; pc.pop_on_fail = 0; - pc.underneath = 0; + pc.on_top = 0; // Only copy the subject if we're *not* on the last case: if (i != cases - has_default - 1) { ADDOP(c, DUP_TOP); } int result = compiler_pattern(c, m->pattern, &pc); RETURN_IF_FALSE(result); - assert(!pc.underneath); + assert(!pc.on_top); NEXT_BLOCK(c); if (pc.stores) { Py_ssize_t i = PyList_GET_SIZE(pc.stores); From d242af1c00bbd07e75b223d3337958be45dcbe65 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 22:49:52 -0700 Subject: [PATCH 14/47] Get or patterns working again. --- Python/compile.c | 50 +++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 0517952e42d4bd..b78a3ff891986c 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5589,10 +5589,8 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); // This object will be stored on success, but needs to be popped on failure: pc->pop_on_fail++; - if (pc->on_top) { - // Rotate this object underneath any items we need to preserve: - ADDOP_I(c, ROTATE, pc->on_top + 1); - } + // Rotate this object underneath any items we need to preserve: + ADDOP_I(c, ROTATE, pc->on_top + 1); return 1; } @@ -5898,12 +5896,21 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // An irrefutable sub-pattern must be last, if it is allowed at all: int is_last = i == size - 1; pc->stores = PySequence_List(stores_init); - pc->allow_irrefutable = allow_irrefutable && is_last; - pc->fail_pop = NULL; - pc->fail_pop_size = 0; - pc->pop_on_fail = 0; - pc->on_top = 0; SET_LOC(c, alt); + if (is_last) { + pc->allow_irrefutable = allow_irrefutable; + pc->fail_pop = fail_pop; + pc->fail_pop_size = fail_pop_size; + pc->pop_on_fail = pop_on_fail; + pc->on_top = on_top; + } + else { + pc->allow_irrefutable = 0; + pc->fail_pop = NULL; + pc->fail_pop_size = 0; + pc->pop_on_fail = 0; + pc->on_top = 0; + } if (pc->stores == NULL || // Only copy the subject if we're *not* on the last alternative: (!is_last && !compiler_addop(c, DUP_TOP)) || @@ -5912,8 +5919,8 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) goto fail; } if (!is_last) { - // TODO: UNROTATE Py_ssize_t nstores = PyList_GET_SIZE(pc->stores) - PyList_GET_SIZE(stores_init); + // TODO: UNROTATE for (Py_ssize_t i = 0; i < nstores; i++) { if (!compiler_addop_i(c, ROTATE, nstores + 1)) { goto fail; @@ -5952,16 +5959,19 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) while (k++ < PyList_GET_SIZE(control)) { ADDOP_I(c, ROTATE, PyList_GET_SIZE(control) - j); // Perfom the same rotation on pc->stores: - PyList_Insert(pc->stores, j, - PySequence_GetItem(pc->stores, -1)); - PySequence_DelItem(pc->stores, -1); + PyObject *last = PyList_GET_ITEM(pc->stores, PyList_GET_SIZE(pc->stores) - 1); + if (PyList_Insert(pc->stores, j, last) || + PySequence_DelItem(pc->stores, -1)) + { + goto fail; + } } } } Py_DECREF(pc->stores); if (!compiler_addop_j(c, JUMP_FORWARD, end) || !compiler_next_block(c) || - !pattern_helper_fail_pop_cleanup(c, pc)) + (!is_last && !pattern_helper_fail_pop_cleanup(c, pc))) { goto fail; } @@ -5969,12 +5979,6 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) Py_XDECREF(stores_init); // Update pc->stores and restore pc->allow_irrefutable: pc->stores = control; - pc->allow_irrefutable = allow_irrefutable; - pc->fail_pop = fail_pop; - pc->fail_pop_size = fail_pop_size; - pc->pop_on_fail = pop_on_fail; - pc->on_top = on_top; - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, JUMP_FORWARD)); compiler_use_next_block(c, end); return 1; diff: @@ -7117,6 +7121,12 @@ optimize_basic_block(basicblock *bb, PyObject *consts) bb->b_exit = 1; } } + break; + case ROTATE: + if (inst->i_oparg < 2) { + inst->i_opcode = NOP; + } + break; } } return 0; From 8c9d7cff2c64963cab4bbbf9464ba14bedda92d7 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 2 Apr 2021 22:59:22 -0700 Subject: [PATCH 15/47] Don't use pop_on_fail anymore --- Python/compile.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index b78a3ff891986c..6b06a27beb3812 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5537,8 +5537,12 @@ pattern_helper_ensure_fail_pop(struct compiler *c, pattern_context *pc, static int pattern_helper_jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) { - RETURN_IF_FALSE(pattern_helper_ensure_fail_pop(c, pc, pc->pop_on_fail)); - ADDOP_JUMP(c, op, pc->fail_pop[pc->pop_on_fail]); + Py_ssize_t pops = pc->on_top; + if (pc->stores) { + pops += PyList_GET_SIZE(pc->stores); + } + RETURN_IF_FALSE(pattern_helper_ensure_fail_pop(c, pc, pops)); + ADDOP_JUMP(c, op, pc->fail_pop[pops]); NEXT_BLOCK(c); return 1; } From 6da075e5b9e42b54060ca82b159f469da1cee338 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 3 Apr 2021 09:38:13 -0700 Subject: [PATCH 16/47] Change ROTATE implementation --- Python/ceval.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 76e5c2aae88847..8acd7eccb8d0c5 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4412,8 +4412,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(ROTATE): { PyObject *top = TOP(); - memmove(&PEEK(oparg - 1), &PEEK(oparg), - sizeof(PyObject*) * (oparg - 1)); + // memmove(&PEEK(oparg - 1), &PEEK(oparg), + // sizeof(PyObject*) * (oparg - 1)); + for (int i = 1; i < oparg; i++) { + PEEK(i) = PEEK(i + 1); + } PEEK(oparg) = top; DISPATCH(); } From 28b72d0ccdde57a9653209e2de1e1825adaf538c Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 3 Apr 2021 18:12:49 -0700 Subject: [PATCH 17/47] Add the ROT_* opcodes back. --- Doc/library/dis.rst | 27 +++++++++----- Include/opcode.h | 3 ++ Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 4 ++- Lib/test/test_peepholer.py | 4 +-- Python/ceval.c | 40 ++++++++++++++++++--- Python/compile.c | 53 +++++++++++++++++----------- Python/importlib.h | 32 ++++++++--------- Python/importlib_external.h | 20 +++++------ Python/importlib_zipimport.h | 6 ++-- Python/opcode_targets.h | 6 ++-- 11 files changed, 128 insertions(+), 69 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 11207ab29d5dfe..c21a667ba17112 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -333,6 +333,25 @@ The Python compiler currently generates the following bytecode instructions. Removes the top-of-stack (TOS) item. +.. opcode:: ROT_TWO + + Swaps the two top-most stack items. + + +.. opcode:: ROT_THREE + + Lifts second and third stack item one position up, moves top down to position + three. + + +.. opcode:: ROT_FOUR + + Lifts second, third and fourth stack items one position up, moves top down + to position four. + + .. versionadded:: 3.8 + + .. opcode:: DUP_TOP Duplicates the reference on top of the stack. @@ -1229,14 +1248,6 @@ All of the following opcodes use their arguments. .. versionadded:: 3.10 -.. opcode:: ROTATE (count) - - Lift the top *count* stack items one position up, and move TOS down to - position *count*. - - .. versionadded:: 3.10 - - .. opcode:: HAVE_ARGUMENT This is not really an opcode. It identifies the dividing line between diff --git a/Include/opcode.h b/Include/opcode.h index 109cc98417897e..07c8427e883e51 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -8,8 +8,11 @@ extern "C" { /* Instruction opcodes for compiled code */ #define POP_TOP 1 +#define ROT_TWO 2 +#define ROT_THREE 3 #define DUP_TOP 4 #define DUP_TOP_TWO 5 +#define ROT_FOUR 6 #define NOP 9 #define UNARY_POSITIVE 10 #define UNARY_NEGATIVE 11 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 1fb8c30c107bdc..6c11fdc4d48ea6 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -315,7 +315,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.10a2 3433 (RERAISE restores f_lasti if oparg != 0) # Python 3.10a6 3434 (PEP 634: Structural Pattern Matching) # Python 3.10a7 3435 Use instruction offsets (as opposed to byte offsets). -# Python 3.10XX 3436 (replace ROT_* with ROTATE) +# Python 3.10XX 3436 (add ROTATE opcode) # # MAGIC must change whenever the bytecode emitted by the compiler may no diff --git a/Lib/opcode.py b/Lib/opcode.py index 311da7d39d4c15..ff0d7a18e79900 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -55,9 +55,11 @@ def jabs_op(name, op): # Blank lines correspond to available opcodes def_op('POP_TOP', 1) - +def_op('ROT_TWO', 2) +def_op('ROT_THREE', 3) def_op('DUP_TOP', 4) def_op('DUP_TOP_TWO', 5) +def_op('ROT_FOUR', 6) def_op('NOP', 9) def_op('UNARY_POSITIVE', 10) diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 61feff360e5c50..4034154e4dcfb5 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -116,8 +116,8 @@ def f(): def test_pack_unpack(self): for line, elem in ( ('a, = a,', 'LOAD_CONST',), - ('a, b = a, b', 'ROTATE',), - ('a, b, c = a, b, c', 'ROTATE',), + ('a, b = a, b', 'ROT_TWO',), + ('a, b, c = a, b, c', 'ROT_THREE',), ): code = compile(line,'','single') self.assertInBytecode(code, elem) diff --git a/Python/ceval.c b/Python/ceval.c index 8acd7eccb8d0c5..545f7ade27e14f 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1888,6 +1888,36 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) DISPATCH(); } + case TARGET(ROT_TWO): { + PyObject *top = TOP(); + PyObject *second = SECOND(); + SET_TOP(second); + SET_SECOND(top); + DISPATCH(); + } + + case TARGET(ROT_THREE): { + PyObject *top = TOP(); + PyObject *second = SECOND(); + PyObject *third = THIRD(); + SET_TOP(second); + SET_SECOND(third); + SET_THIRD(top); + DISPATCH(); + } + + case TARGET(ROT_FOUR): { + PyObject *top = TOP(); + PyObject *second = SECOND(); + PyObject *third = THIRD(); + PyObject *fourth = FOURTH(); + SET_TOP(second); + SET_SECOND(third); + SET_THIRD(fourth); + SET_FOURTH(top); + DISPATCH(); + } + case TARGET(DUP_TOP): { PyObject *top = TOP(); Py_INCREF(top); @@ -4412,11 +4442,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) case TARGET(ROTATE): { PyObject *top = TOP(); - // memmove(&PEEK(oparg - 1), &PEEK(oparg), - // sizeof(PyObject*) * (oparg - 1)); - for (int i = 1; i < oparg; i++) { - PEEK(i) = PEEK(i + 1); - } + memmove(&PEEK(oparg - 1), &PEEK(oparg), + sizeof(PyObject*) * (oparg - 1)); + // for (int i = 1; i < oparg; i++) { + // PEEK(i) = PEEK(i + 1); + // } PEEK(oparg) = top; DISPATCH(); } diff --git a/Python/compile.c b/Python/compile.c index 6b06a27beb3812..5e20d817d36f26 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -928,6 +928,10 @@ stack_effect(int opcode, int oparg, int jump) /* Stack manipulation */ case POP_TOP: return -1; + case ROT_TWO: + case ROT_THREE: + case ROT_FOUR: + return 0; case DUP_TOP: return 1; case DUP_TOP_TWO: @@ -1721,7 +1725,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case FOR_LOOP: /* Pop the iterator */ if (preserve_tos) { - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); } ADDOP(c, POP_TOP); return 1; @@ -1751,13 +1755,13 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case FINALLY_END: if (preserve_tos) { - ADDOP_I(c, ROTATE, 4); + ADDOP(c, ROT_FOUR); } ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); if (preserve_tos) { - ADDOP_I(c, ROTATE, 4); + ADDOP(c, ROT_FOUR); } ADDOP(c, POP_EXCEPT); return 1; @@ -1766,7 +1770,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case ASYNC_WITH: ADDOP(c, POP_BLOCK); if (preserve_tos) { - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); } if(!compiler_call_exit_with_nones(c)) { return 0; @@ -1784,7 +1788,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, ADDOP(c, POP_BLOCK); } if (preserve_tos) { - ADDOP_I(c, ROTATE, 4); + ADDOP(c, ROT_FOUR); } ADDOP(c, POP_EXCEPT); if (info->fb_datum) { @@ -1796,7 +1800,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case POP_VALUE: if (preserve_tos) { - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); } ADDOP(c, POP_TOP); return 1; @@ -2627,7 +2631,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP(c, DUP_TOP); - ADDOP_I(c, ROTATE, 3); + ADDOP(c, ROT_THREE); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, cleanup); NEXT_BLOCK(c); @@ -3231,7 +3235,7 @@ compiler_import_as(struct compiler *c, identifier name, identifier asname) if (dot == -1) { break; } - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); ADDOP(c, POP_TOP); } if (!compiler_nameop(c, asname, Store)) { @@ -3997,7 +4001,7 @@ compiler_compare(struct compiler *c, expr_ty e) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP(c, DUP_TOP); - ADDOP_I(c, ROTATE, 3); + ADDOP(c, ROT_THREE); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, cleanup); NEXT_BLOCK(c); @@ -4009,7 +4013,7 @@ compiler_compare(struct compiler *c, expr_ty e) return 0; ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); compiler_use_next_block(c, cleanup); - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); ADDOP(c, POP_TOP); compiler_use_next_block(c, end); } @@ -5236,11 +5240,11 @@ compiler_augassign(struct compiler *c, stmt_ty s) switch (e->kind) { case Attribute_kind: c->u->u_lineno = e->end_lineno; - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); break; case Subscript_kind: - ADDOP_I(c, ROTATE, 3); + ADDOP(c, ROT_THREE); ADDOP(c, STORE_SUBSCR); break; case Name_kind: @@ -6983,15 +6987,12 @@ optimize_basic_block(basicblock *bb, PyObject *consts) bb->b_instr[i+1].i_opcode = NOP; break; case 2: - inst->i_opcode = ROTATE; - inst->i_oparg = 2; + inst->i_opcode = ROT_TWO; bb->b_instr[i+1].i_opcode = NOP; break; case 3: - inst->i_opcode = ROTATE; - inst->i_oparg = 3; - bb->b_instr[i+1].i_opcode = ROTATE; - bb->b_instr[i+1].i_oparg = 2; + inst->i_opcode = ROT_THREE; + bb->b_instr[i+1].i_opcode = ROT_TWO; } break; } @@ -7127,8 +7128,20 @@ optimize_basic_block(basicblock *bb, PyObject *consts) } break; case ROTATE: - if (inst->i_oparg < 2) { - inst->i_opcode = NOP; + switch (oparg) { + case 0: + case 1: + inst->i_opcode = NOP; + break; + case 2: + inst->i_opcode = ROT_TWO; + break; + case 3: + inst->i_opcode = ROT_THREE; + break; + case 4: + inst->i_opcode = ROT_FOUR; + break; } break; } diff --git a/Python/importlib.h b/Python/importlib.h index 0521ab6cecc465..f3604071367683 100644 --- a/Python/importlib.h +++ b/Python/importlib.h @@ -56,7 +56,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8, 0,0,0,67,0,0,0,115,38,0,0,0,122,4,124,0, 106,0,87,0,83,0,4,0,116,1,121,18,1,0,1,0, - 1,0,116,2,124,0,131,1,106,0,99,4,89,0,83,0, + 1,0,116,2,124,0,131,1,106,0,6,0,89,0,83,0, 119,0,169,1,78,41,3,218,12,95,95,113,117,97,108,110, 97,109,101,95,95,218,14,65,116,116,114,105,98,117,116,101, 69,114,114,111,114,218,4,116,121,112,101,41,1,218,3,111, @@ -154,11 +154,11 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 60,0,122,86,9,0,124,0,106,3,143,63,1,0,124,0, 106,4,100,2,107,2,115,24,124,0,106,5,124,1,107,2, 114,46,124,1,124,0,95,5,124,0,4,0,106,4,100,3, - 55,0,99,2,95,4,87,0,100,4,4,0,4,0,131,3, + 55,0,2,0,95,4,87,0,100,4,4,0,4,0,131,3, 1,0,87,0,116,2,124,1,61,0,100,1,83,0,124,0, 160,6,161,0,114,56,116,7,100,5,124,0,22,0,131,1, 130,1,124,0,106,8,160,9,100,6,161,1,114,69,124,0, - 4,0,106,10,100,3,55,0,99,2,95,10,87,0,100,4, + 4,0,106,10,100,3,55,0,2,0,95,10,87,0,100,4, 4,0,4,0,131,3,1,0,110,8,49,0,115,79,119,1, 1,0,1,0,1,0,89,0,1,0,124,0,106,8,160,9, 161,0,1,0,124,0,106,8,160,11,161,0,1,0,113,10, @@ -192,10 +192,10 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 115,144,0,0,0,116,0,160,1,161,0,125,1,124,0,106, 2,143,55,1,0,124,0,106,3,124,1,107,3,114,17,116, 4,100,1,131,1,130,1,124,0,106,5,100,2,107,4,115, - 24,74,0,130,1,124,0,4,0,106,5,100,3,56,0,99, - 2,95,5,124,0,106,5,100,2,107,2,114,54,100,0,124, + 24,74,0,130,1,124,0,4,0,106,5,100,3,56,0,2, + 0,95,5,124,0,106,5,100,2,107,2,114,54,100,0,124, 0,95,3,124,0,106,6,114,54,124,0,4,0,106,6,100, - 3,56,0,99,2,95,6,124,0,106,7,160,8,161,0,1, + 3,56,0,2,0,95,6,124,0,106,7,160,8,161,0,1, 0,87,0,100,0,4,0,4,0,131,3,1,0,100,0,83, 0,49,0,115,65,119,1,1,0,1,0,1,0,89,0,1, 0,100,0,83,0,41,4,78,250,31,99,97,110,110,111,116, @@ -248,7 +248,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 100,117,108,101,76,111,99,107,46,95,95,105,110,105,116,95, 95,99,1,0,0,0,0,0,0,0,0,0,0,0,1,0, 0,0,3,0,0,0,67,0,0,0,115,18,0,0,0,124, - 0,4,0,106,0,100,1,55,0,99,2,95,0,100,2,83, + 0,4,0,106,0,100,1,55,0,2,0,95,0,100,2,83, 0,41,3,78,114,42,0,0,0,84,41,1,114,30,0,0, 0,114,52,0,0,0,114,5,0,0,0,114,5,0,0,0, 114,6,0,0,0,114,43,0,0,0,150,0,0,0,115,6, @@ -257,7 +257,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 105,114,101,99,1,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,0,3,0,0,0,67,0,0,0,115,36,0,0, 0,124,0,106,0,100,1,107,2,114,9,116,1,100,2,131, - 1,130,1,124,0,4,0,106,0,100,3,56,0,99,2,95, + 1,130,1,124,0,4,0,106,0,100,3,56,0,2,0,95, 0,100,0,83,0,41,4,78,114,25,0,0,0,114,46,0, 0,0,114,42,0,0,0,41,2,114,30,0,0,0,114,47, 0,0,0,114,52,0,0,0,114,5,0,0,0,114,5,0, @@ -529,8 +529,8 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 1,0,1,0,1,0,100,5,125,3,89,0,122,5,124,0, 106,7,125,4,87,0,110,25,4,0,116,6,121,89,1,0, 1,0,1,0,124,1,100,2,117,0,114,75,100,6,160,8, - 124,3,161,1,99,4,89,0,83,0,100,7,160,8,124,3, - 124,1,161,2,99,4,89,0,83,0,100,8,160,8,124,3, + 124,3,161,1,6,0,89,0,83,0,100,7,160,8,124,3, + 124,1,161,2,6,0,89,0,83,0,100,8,160,8,124,3, 124,4,161,2,83,0,119,0,119,0,119,0,41,9,122,44, 84,104,101,32,105,109,112,108,101,109,101,110,116,97,116,105, 111,110,32,111,102,32,77,111,100,117,108,101,84,121,112,101, @@ -705,7 +705,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 107,2,111,38,124,2,124,1,106,0,107,2,111,38,124,0, 106,4,124,1,106,4,107,2,111,38,124,0,106,5,124,1, 106,5,107,2,87,0,83,0,4,0,116,6,121,50,1,0, - 1,0,1,0,116,7,99,4,89,0,83,0,119,0,114,0, + 1,0,1,0,116,7,6,0,89,0,83,0,119,0,114,0, 0,0,0,41,8,114,129,0,0,0,114,20,0,0,0,114, 122,0,0,0,114,126,0,0,0,218,6,99,97,99,104,101, 100,218,12,104,97,115,95,108,111,99,97,116,105,111,110,114, @@ -1047,7 +1047,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 254,2,245,255,128,114,173,0,0,0,99,1,0,0,0,0, 0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,67, 0,0,0,115,54,0,0,0,116,0,124,0,106,1,131,1, - 143,12,1,0,116,2,124,0,131,1,87,0,99,2,100,1, + 143,12,1,0,116,2,124,0,131,1,87,0,2,0,100,1, 4,0,4,0,131,3,1,0,83,0,49,0,115,20,119,1, 1,0,1,0,1,0,89,0,1,0,100,1,83,0,41,2, 122,191,82,101,116,117,114,110,32,97,32,110,101,119,32,109, @@ -1449,9 +1449,9 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 4,115,131,124,0,116,0,106,6,118,0,114,131,116,0,106, 6,124,0,25,0,125,8,122,5,124,8,106,11,125,9,87, 0,110,12,4,0,116,9,121,138,1,0,1,0,1,0,124, - 7,99,4,89,0,99,2,1,0,83,0,124,9,100,1,117, - 0,114,127,124,7,99,2,1,0,83,0,124,9,99,2,1, - 0,83,0,124,7,99,2,1,0,83,0,113,26,100,1,83, + 7,6,0,89,0,2,0,1,0,83,0,124,9,100,1,117, + 0,114,127,124,7,2,0,1,0,83,0,124,9,2,0,1, + 0,83,0,124,7,2,0,1,0,83,0,113,26,100,1,83, 0,119,0,119,0,41,4,122,21,70,105,110,100,32,97,32, 109,111,100,117,108,101,39,115,32,115,112,101,99,46,78,122, 53,115,121,115,46,109,101,116,97,95,112,97,116,104,32,105, @@ -1551,7 +1551,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,4,0,0,0,8,0,0,0,67,0,0,0,115,128,0, 0,0,116,0,124,0,131,1,143,31,1,0,116,1,106,2, 160,3,124,0,116,4,161,2,125,2,124,2,116,4,117,0, - 114,28,116,5,124,0,124,1,131,2,87,0,99,2,100,1, + 114,28,116,5,124,0,124,1,131,2,87,0,2,0,100,1, 4,0,4,0,131,3,1,0,83,0,87,0,100,1,4,0, 4,0,131,3,1,0,110,8,49,0,115,38,119,1,1,0, 1,0,1,0,89,0,1,0,124,2,100,1,117,0,114,58, diff --git a/Python/importlib_external.h b/Python/importlib_external.h index b467958b27134e..0532dc233acf63 100644 --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -196,7 +196,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 102,2,83,0,116,4,124,0,131,1,68,0,93,21,125,4, 124,4,116,1,118,0,114,43,124,0,106,5,124,4,100,1, 100,2,141,2,92,2,125,1,125,3,124,1,124,3,102,2, - 99,2,1,0,83,0,113,22,100,3,124,0,102,2,83,0, + 2,0,1,0,83,0,113,22,100,3,124,0,102,2,83,0, 41,5,122,32,82,101,112,108,97,99,101,109,101,110,116,32, 102,111,114,32,111,115,46,112,97,116,104,46,115,112,108,105, 116,40,41,46,114,3,0,0,0,41,1,90,8,109,97,120, @@ -1015,7 +1015,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,115,50,0,0,0,122,8,116,0,160,1,116,0,106,2, 124,0,161,2,87,0,83,0,4,0,116,3,121,24,1,0, 1,0,1,0,116,0,160,1,116,0,106,4,124,0,161,2, - 99,4,89,0,83,0,119,0,114,121,0,0,0,41,5,218, + 6,0,89,0,83,0,119,0,114,121,0,0,0,41,5,218, 6,119,105,110,114,101,103,90,7,79,112,101,110,75,101,121, 90,17,72,75,69,89,95,67,85,82,82,69,78,84,95,85, 83,69,82,114,64,0,0,0,90,18,72,75,69,89,95,76, @@ -1062,8 +1062,8 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,1,0,1,0,89,0,100,0,83,0,116,3,131,0,68, 0,93,26,92,2,125,5,125,6,124,4,160,4,116,5,124, 6,131,1,161,1,114,56,116,6,106,7,124,1,124,5,124, - 1,124,4,131,2,124,4,100,1,141,3,125,7,124,7,99, - 2,1,0,83,0,113,30,100,0,83,0,119,0,41,2,78, + 1,124,4,131,2,124,4,100,1,141,3,125,7,124,7,2, + 0,1,0,83,0,113,30,100,0,83,0,119,0,41,2,78, 114,191,0,0,0,41,8,114,211,0,0,0,114,63,0,0, 0,114,64,0,0,0,114,195,0,0,0,114,122,0,0,0, 114,123,0,0,0,114,146,0,0,0,218,16,115,112,101,99, @@ -1504,10 +1504,10 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,67,0,0,0,115,128,0,0,0,116,0,124,0, 116,1,116,2,102,2,131,2,114,36,116,3,160,4,116,5, 124,1,131,1,161,1,143,12,125,2,124,2,160,6,161,0, - 87,0,99,2,100,1,4,0,4,0,131,3,1,0,83,0, + 87,0,2,0,100,1,4,0,4,0,131,3,1,0,83,0, 49,0,115,29,119,1,1,0,1,0,1,0,89,0,1,0, 100,1,83,0,116,3,160,7,124,1,100,2,161,2,143,12, - 125,2,124,2,160,6,161,0,87,0,99,2,100,1,4,0, + 125,2,124,2,160,6,161,0,87,0,2,0,100,1,4,0, 4,0,131,3,1,0,83,0,49,0,115,57,119,1,1,0, 1,0,1,0,89,0,1,0,100,1,83,0,41,3,122,39, 82,101,116,117,114,110,32,116,104,101,32,100,97,116,97,32, @@ -2106,7 +2106,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 9,0,0,0,67,0,0,0,115,76,0,0,0,116,0,106, 1,100,1,117,1,114,14,116,0,106,1,115,14,116,2,160, 3,100,2,116,4,161,2,1,0,116,0,106,1,68,0,93, - 17,125,1,122,7,124,1,124,0,131,1,87,0,99,2,1, + 17,125,1,122,7,124,1,124,0,131,1,87,0,2,0,1, 0,83,0,4,0,116,5,121,37,1,0,1,0,1,0,89, 0,113,17,100,1,83,0,119,0,41,3,122,46,83,101,97, 114,99,104,32,115,121,115,46,112,97,116,104,95,104,111,111, @@ -2188,7 +2188,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 100,2,131,2,114,35,124,6,160,5,124,1,124,3,161,2, 125,7,110,6,124,0,160,6,124,1,124,6,161,2,125,7, 124,7,100,1,117,0,114,46,113,4,124,7,106,7,100,1, - 117,1,114,55,124,7,99,2,1,0,83,0,124,7,106,8, + 117,1,114,55,124,7,2,0,1,0,83,0,124,7,106,8, 125,8,124,8,100,1,117,0,114,66,116,9,100,3,131,1, 130,1,124,4,160,10,124,8,161,1,1,0,113,4,116,11, 160,12,124,1,100,1,161,2,125,7,124,4,124,7,95,8, @@ -2414,13 +2414,13 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,93,29,92,2,125,9,125,10,100,5,124,9,23,0,125, 11,116,13,124,8,124,11,131,2,125,12,116,15,124,12,131, 1,114,101,124,0,160,16,124,10,124,1,124,12,124,8,103, - 1,124,2,161,5,99,2,1,0,83,0,113,72,116,17,124, + 1,124,2,161,5,2,0,1,0,83,0,113,72,116,17,124, 8,131,1,125,3,124,0,106,14,68,0,93,41,92,2,125, 9,125,10,116,13,124,0,106,2,124,4,124,9,23,0,131, 2,125,12,116,18,106,19,100,6,124,12,100,3,100,7,141, 3,1,0,124,7,124,9,23,0,124,6,118,0,114,150,116, 15,124,12,131,1,114,150,124,0,160,16,124,10,124,1,124, - 12,100,8,124,2,161,5,99,2,1,0,83,0,113,109,124, + 12,100,8,124,2,161,5,2,0,1,0,83,0,113,109,124, 3,114,171,116,18,160,19,100,9,124,8,161,2,1,0,116, 18,160,20,124,1,100,8,161,2,125,13,124,8,103,1,124, 13,95,21,124,13,83,0,100,8,83,0,119,0,41,10,122, diff --git a/Python/importlib_zipimport.h b/Python/importlib_zipimport.h index 2cbbf04301a976..7997df0cc7af5a 100644 --- a/Python/importlib_zipimport.h +++ b/Python/importlib_zipimport.h @@ -136,7 +136,7 @@ const unsigned char _Py_M__zipimport[] = { 0,89,0,124,7,124,0,95,18,124,1,124,0,95,19,116, 8,106,20,124,3,100,0,100,0,100,8,133,3,25,0,142, 0,124,0,95,21,124,0,106,21,114,141,124,0,4,0,106, - 21,116,7,55,0,99,2,95,21,100,0,83,0,100,0,83, + 21,116,7,55,0,2,0,95,21,100,0,83,0,100,0,83, 0,119,0,119,0,41,9,78,114,0,0,0,0,122,21,97, 114,99,104,105,118,101,32,112,97,116,104,32,105,115,32,101, 109,112,116,121,169,1,218,4,112,97,116,104,84,122,14,110, @@ -588,7 +588,7 @@ const unsigned char _Py_M__zipimport[] = { 67,0,0,0,115,56,0,0,0,116,0,124,0,124,1,131, 2,125,2,116,1,68,0,93,18,92,3,125,3,125,4,125, 5,124,2,124,3,23,0,125,6,124,6,124,0,106,2,118, - 0,114,25,124,5,99,2,1,0,83,0,113,7,100,0,83, + 0,114,25,124,5,2,0,1,0,83,0,113,7,100,0,83, 0,114,93,0,0,0,41,3,114,36,0,0,0,218,16,95, 122,105,112,95,115,101,97,114,99,104,111,114,100,101,114,114, 28,0,0,0,41,7,114,32,0,0,0,114,38,0,0,0, @@ -996,7 +996,7 @@ const unsigned char _Py_M__zipimport[] = { 0,100,0,125,12,126,12,110,9,100,0,125,12,126,12,119, 1,116,11,124,9,124,10,131,2,125,11,124,11,100,0,117, 0,114,99,113,9,124,8,100,4,25,0,125,9,124,11,124, - 6,124,9,102,3,99,2,1,0,83,0,124,3,114,124,100, + 6,124,9,102,3,2,0,1,0,83,0,124,3,114,124,100, 5,124,3,155,0,157,2,125,13,116,12,124,13,124,1,100, 6,141,2,124,3,130,2,116,12,100,7,124,1,155,2,157, 2,124,1,100,6,141,2,130,1,119,0,119,0,41,8,78, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 5d118412642156..57d1fa9c3de981 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -1,11 +1,11 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&TARGET_POP_TOP, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_ROT_TWO, + &&TARGET_ROT_THREE, &&TARGET_DUP_TOP, &&TARGET_DUP_TOP_TWO, - &&_unknown_opcode, + &&TARGET_ROT_FOUR, &&_unknown_opcode, &&_unknown_opcode, &&TARGET_NOP, From fa0068a1fef8d39071eb5b457cdd5fe3ace90c2f Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 3 Apr 2021 21:17:37 -0700 Subject: [PATCH 18/47] ROTATE -> ROT_N and ditch pc->pop_on_fail --- Include/opcode.h | 2 +- Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 2 +- Python/ceval.c | 2 +- Python/compile.c | 115 +++++++++------------------ Python/opcode_targets.h | 2 +- Python/pyhash.c | 10 +-- 7 files changed, 48 insertions(+), 87 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index 07c8427e883e51..339d3ce1c6cff8 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -81,7 +81,7 @@ extern "C" { #define DELETE_ATTR 96 #define STORE_GLOBAL 97 #define DELETE_GLOBAL 98 -#define ROTATE 99 +#define ROT_N 99 #define LOAD_CONST 100 #define LOAD_NAME 101 #define BUILD_TUPLE 102 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 6c11fdc4d48ea6..743beb772157c3 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -315,7 +315,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.10a2 3433 (RERAISE restores f_lasti if oparg != 0) # Python 3.10a6 3434 (PEP 634: Structural Pattern Matching) # Python 3.10a7 3435 Use instruction offsets (as opposed to byte offsets). -# Python 3.10XX 3436 (add ROTATE opcode) +# Python 3.10XX 3436 (add ROT_N opcode) # # MAGIC must change whenever the bytecode emitted by the compiler may no diff --git a/Lib/opcode.py b/Lib/opcode.py index ff0d7a18e79900..38729762a24dc8 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -139,7 +139,7 @@ def jabs_op(name, op): name_op('DELETE_ATTR', 96) # "" name_op('STORE_GLOBAL', 97) # "" name_op('DELETE_GLOBAL', 98) # "" -def_op('ROTATE', 99) +def_op('ROT_N', 99) def_op('LOAD_CONST', 100) # Index in const list hasconst.append(100) diff --git a/Python/ceval.c b/Python/ceval.c index 545f7ade27e14f..6c1675bed353e9 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4440,7 +4440,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) DISPATCH(); } - case TARGET(ROTATE): { + case TARGET(ROT_N): { PyObject *top = TOP(); memmove(&PEEK(oparg - 1), &PEEK(oparg), sizeof(PyObject*) * (oparg - 1)); diff --git a/Python/compile.c b/Python/compile.c index 5e20d817d36f26..97ab0f205d52d3 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -207,9 +207,9 @@ typedef struct { PyObject *stores; // If 0, any name captures against our subject will raise. int allow_irrefutable; - // An array of blocks to jump to on failure. fail_pop[i] will pop i items - // off of the stack. The end result looks like this (with each block falling - // through to the next): + // An array of blocks to jump to on failure. Jumping to fail_pop[i] will pop + // i items off of the stack. The end result looks like this (with each block + // falling through to the next): // fail_pop[4]: POP_TOP // fail_pop[3]: POP_TOP // fail_pop[2]: POP_TOP @@ -218,12 +218,9 @@ typedef struct { basicblock **fail_pop; // The current length of fail_pop. Py_ssize_t fail_pop_size; - // How many items should be popped on failure, since subpatterns often need - // to clean up for their parents. Typical usage looks like: - // ADDOP_JUMP(c, JUMP_ABSOLUTE, pc->fail_pop[pc->pop_on_fail]); - Py_ssize_t pop_on_fail; // The number of items on top of the stack that need to *stay* on top of the - // stack. Variable captures go beneath these. + // stack. Variable captures go beneath these. All of them will be popped on + // failure. Py_ssize_t on_top; } pattern_context; @@ -1175,7 +1172,7 @@ stack_effect(int opcode, int oparg, int jump) return 1; case MATCH_KEYS: return 2; - case ROTATE: + case ROT_N: return 0; default: return PY_INVALID_STACK_EFFECT; @@ -5496,8 +5493,6 @@ compiler_slice(struct compiler *c, expr_ty s) // TODO: this comment // TODO: other comments -// TODO: ROTATE perf tests -// TODO: POP op? perf tests // TODO: check for memory leaks // TODO: variants of test_patma_282 with mappings, classes, stars, stores before/after @@ -5595,10 +5590,8 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) } } RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); - // This object will be stored on success, but needs to be popped on failure: - pc->pop_on_fail++; // Rotate this object underneath any items we need to preserve: - ADDOP_I(c, ROTATE, pc->on_top + 1); + ADDOP_I(c, ROT_N, pc->on_top + 1); return 1; } @@ -5609,14 +5602,11 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, { RETURN_IF_FALSE(unpack_helper(c, values)); Py_ssize_t size = asdl_seq_LEN(values); - // We've now got a bunch of new subjects on the stack. If any of them fail - // to match, we need to pop everything else off: - pc->pop_on_fail += size; - // They need to remain on top of the stack after each subpattern match: + // We've now got a bunch of new subjects on the stack. They need to remain + // there after each subpattern match: pc->on_top += size; for (Py_ssize_t i = 0; i < size; i++) { // One less item to keep track of each time we loop through: - pc->pop_on_fail--; pc->on_top--; expr_ty value = asdl_seq_GET(values, i); if (i == star) { @@ -5658,10 +5648,8 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, ADDOP(c, BINARY_SUBTRACT); } ADDOP(c, BINARY_SUBSCR); - pc->pop_on_fail++; pc->on_top++; RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); - pc->pop_on_fail--; pc->on_top--; NEXT_BLOCK(c); } @@ -5688,10 +5676,8 @@ compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) assert(p->kind == MatchAs_kind); // Need to make a copy for (possibly) storing later: ADDOP(c, DUP_TOP); - pc->pop_on_fail++; pc->on_top++; RETURN_IF_FALSE(compiler_pattern(c, p->v.MatchAs.pattern, pc)); - pc->pop_on_fail--; pc->on_top--; NEXT_BLOCK(c); RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.MatchAs.name, pc)); @@ -5738,10 +5724,8 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) } ADDOP_LOAD_CONST_NEW(c, kwnames); ADDOP_I(c, MATCH_CLASS, nargs); - pc->pop_on_fail++; pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->pop_on_fail--; pc->on_top--; // TOS is now a tuple of (nargs + nkwargs) attributes. for (i = 0; i < nargs + nkwargs; i++) { @@ -5761,10 +5745,8 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, DUP_TOP); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); - pc->pop_on_fail++; pc->on_top++; RETURN_IF_FALSE(compiler_pattern_subpattern(c, arg, pc)); - pc->pop_on_fail--; pc->on_top--; NEXT_BLOCK(c); } @@ -5798,10 +5780,8 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) // A starred pattern will be a keyless value. It is guaranteed to be last: int star = size ? !asdl_seq_GET(keys, size - 1) : 0; ADDOP(c, MATCH_MAPPING); - pc->pop_on_fail++; pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->pop_on_fail--; pc->on_top--; if (!size) { // If the pattern is just "{}", we're done! @@ -5813,10 +5793,8 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - star)); ADDOP_COMPARE(c, GtE); - pc->pop_on_fail++; pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->pop_on_fail--; pc->on_top--; } if (INT_MAX < size - star - 1) { @@ -5835,11 +5813,9 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) } ADDOP_I(c, BUILD_TUPLE, size - star); ADDOP(c, MATCH_KEYS); - pc->pop_on_fail += 3; - pc->on_top+=3; + pc->on_top += 3; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->pop_on_fail -= 3; - pc->on_top-=3; + pc->on_top -= 3; // So far so good. There's now a tuple of values on the stack to match // sub-patterns against: for (Py_ssize_t i = 0; i < size - star; i++) { @@ -5850,10 +5826,8 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, DUP_TOP); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); - pc->pop_on_fail += 3; pc->on_top += 3; RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); - pc->pop_on_fail -= 3; pc->on_top -= 3; } // If we get this far, it's a match! We're done with that tuple of values. @@ -5862,10 +5836,8 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) // If we had a starred name, bind a dict of remaining items to it: ADDOP(c, COPY_DICT_WITHOUT_KEYS); PyObject *id = asdl_seq_GET(values, size - 1)->v.Name.id; - pc->pop_on_fail++; pc->on_top++; RETURN_IF_FALSE(pattern_helper_store_name(c, id, pc)); - pc->pop_on_fail--; pc->on_top--; } else { @@ -5896,8 +5868,9 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) int allow_irrefutable = pc->allow_irrefutable; basicblock **fail_pop = pc->fail_pop; Py_ssize_t fail_pop_size = pc->fail_pop_size; - Py_ssize_t pop_on_fail = pc->pop_on_fail; Py_ssize_t on_top = pc->on_top; + Py_ssize_t nstores_init = PyList_GET_SIZE(stores_init); + Py_ssize_t ncontrol = 0; for (Py_ssize_t i = 0; i < size; i++) { // NOTE: Can't use our nice returning macros here: they'll leak lists! expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); @@ -5909,14 +5882,12 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) pc->allow_irrefutable = allow_irrefutable; pc->fail_pop = fail_pop; pc->fail_pop_size = fail_pop_size; - pc->pop_on_fail = pop_on_fail; pc->on_top = on_top; } else { pc->allow_irrefutable = 0; pc->fail_pop = NULL; pc->fail_pop_size = 0; - pc->pop_on_fail = 0; pc->on_top = 0; } if (pc->stores == NULL || @@ -5926,11 +5897,10 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) { goto fail; } + Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); if (!is_last) { - Py_ssize_t nstores = PyList_GET_SIZE(pc->stores) - PyList_GET_SIZE(stores_init); - // TODO: UNROTATE - for (Py_ssize_t i = 0; i < nstores; i++) { - if (!compiler_addop_i(c, ROTATE, nstores + 1)) { + for (Py_ssize_t i = 0; i < nstores - nstores_init; i++) { + if (!compiler_addop_i(c, ROT_N, nstores - nstores_init + 1)) { goto fail; } } @@ -5942,37 +5912,39 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // If this is the first alternative, save its stores as a "control" // for the others (they can't bind a different set of names): control = pc->stores; + ncontrol = nstores; Py_INCREF(control); } - else if (PyList_GET_SIZE(pc->stores) != PyList_GET_SIZE(control)) { + else if (nstores != ncontrol) { goto diff; } - else if (PyList_GET_SIZE(stores_init) < PyList_GET_SIZE(pc->stores)) { + else if (nstores_init < nstores) { // Otherwise, check to see if we differ from the control list: - Py_ssize_t j, k; - for (j = PyList_GET_SIZE(stores_init); j < PyList_GET_SIZE(control); - j++) - { - k = PySequence_Index(pc->stores, PyList_GET_ITEM(control, j)); + for (Py_ssize_t j = nstores_init; j < nstores; j++) { + PyObject *name = PyList_GET_ITEM(control, j); + Py_ssize_t k = PySequence_Index(pc->stores, name); if (k < 0) { PyErr_Clear(); goto diff; } - assert(j <= k); // Reorder the names on the stack to match the order of the // names in control. This is potentially very inefficient when // each alternative subpattern binds lots of names in different // orders, but it's fine for reasonable cases. There's probably // a better way of doing this, though. - while (k++ < PyList_GET_SIZE(control)) { - ADDOP_I(c, ROTATE, PyList_GET_SIZE(control) - j); - // Perfom the same rotation on pc->stores: - PyObject *last = PyList_GET_ITEM(pc->stores, PyList_GET_SIZE(pc->stores) - 1); - if (PyList_Insert(pc->stores, j, last) || - PySequence_DelItem(pc->stores, -1)) - { - goto fail; - } + assert(j <= k); + // Perfom the same rotation on pc->stores: + PyObject *rotate = PyList_GetSlice(pc->stores, k, nstores); + if (rotate == NULL || + PyList_SetSlice(pc->stores, k, nstores, NULL) || + PyList_SetSlice(pc->stores, j, j, rotate)) + { + Py_XDECREF(rotate); + goto fail; + } + Py_DECREF(rotate); + while (k++ < ncontrol) { + ADDOP_I(c, ROT_N, ncontrol - j); } } } @@ -6022,34 +5994,24 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) } only_wildcard &= WILDCARD_CHECK(value); } - ADDOP(c, MATCH_SEQUENCE); - pc->pop_on_fail++; pc->on_top++; + ADDOP(c, MATCH_SEQUENCE); RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->pop_on_fail--; - pc->on_top--; if (star < 0) { // No star: len(subject) == size ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size)); ADDOP_COMPARE(c, Eq); - pc->pop_on_fail++; - pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->pop_on_fail--; - pc->on_top--; } else if (size > 1) { // Star: len(subject) >= size - 1 ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - 1)); ADDOP_COMPARE(c, GtE); - pc->pop_on_fail++; - pc->on_top++; RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->pop_on_fail--; - pc->on_top--; } + pc->on_top--; if (only_wildcard) { // Patterns like: [] / [_] / [_, _] / [*_] / [_, *_] / [_, _, *_] / etc. ADDOP(c, POP_TOP); @@ -6152,7 +6114,6 @@ compiler_match(struct compiler *c, stmt_ty s) pc.allow_irrefutable = m->guard != NULL || i == cases - 1; pc.fail_pop = NULL; pc.fail_pop_size = 0; - pc.pop_on_fail = 0; pc.on_top = 0; // Only copy the subject if we're *not* on the last case: if (i != cases - has_default - 1) { @@ -7127,7 +7088,7 @@ optimize_basic_block(basicblock *bb, PyObject *consts) } } break; - case ROTATE: + case ROT_N: switch (oparg) { case 0: case 1: diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 57d1fa9c3de981..d19337b55a464d 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -98,7 +98,7 @@ static void *opcode_targets[256] = { &&TARGET_DELETE_ATTR, &&TARGET_STORE_GLOBAL, &&TARGET_DELETE_GLOBAL, - &&TARGET_ROTATE, + &&TARGET_ROT_N, &&TARGET_LOAD_CONST, &&TARGET_LOAD_NAME, &&TARGET_BUILD_TUPLE, diff --git a/Python/pyhash.c b/Python/pyhash.c index 3b6c34eefd515a..a14d8bafb7b968 100644 --- a/Python/pyhash.c +++ b/Python/pyhash.c @@ -347,16 +347,16 @@ static PyHash_FuncDef PyHash_Func = {fnv, "fnv", 8 * SIZEOF_PY_HASH_T, #ifdef _MSC_VER -# define ROTATE(x, b) _rotl64(x, b) +# define ROT_N(x, b) _rotl64(x, b) #else -# define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) +# define ROT_N(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) #endif #define HALF_ROUND(a,b,c,d,s,t) \ a += b; c += d; \ - b = ROTATE(b, s) ^ a; \ - d = ROTATE(d, t) ^ c; \ - a = ROTATE(a, 32); + b = ROT_N(b, s) ^ a; \ + d = ROT_N(d, t) ^ c; \ + a = ROT_N(a, 32); #define DOUBLE_ROUND(v0,v1,v2,v3) \ HALF_ROUND(v0,v1,v2,v3,13,16); \ From 28cd4d86122143324c902735650b7b0a6cb9f979 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 3 Apr 2021 21:30:11 -0700 Subject: [PATCH 19/47] Fix bad find-and-replace --- Lib/opcode.py | 1 - Python/pyhash.c | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Lib/opcode.py b/Lib/opcode.py index 38729762a24dc8..6844c802485135 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -140,7 +140,6 @@ def jabs_op(name, op): name_op('STORE_GLOBAL', 97) # "" name_op('DELETE_GLOBAL', 98) # "" def_op('ROT_N', 99) - def_op('LOAD_CONST', 100) # Index in const list hasconst.append(100) name_op('LOAD_NAME', 101) # Index in name list diff --git a/Python/pyhash.c b/Python/pyhash.c index a14d8bafb7b968..3b6c34eefd515a 100644 --- a/Python/pyhash.c +++ b/Python/pyhash.c @@ -347,16 +347,16 @@ static PyHash_FuncDef PyHash_Func = {fnv, "fnv", 8 * SIZEOF_PY_HASH_T, #ifdef _MSC_VER -# define ROT_N(x, b) _rotl64(x, b) +# define ROTATE(x, b) _rotl64(x, b) #else -# define ROT_N(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) +# define ROTATE(x, b) (uint64_t)( ((x) << (b)) | ( (x) >> (64 - (b))) ) #endif #define HALF_ROUND(a,b,c,d,s,t) \ a += b; c += d; \ - b = ROT_N(b, s) ^ a; \ - d = ROT_N(d, t) ^ c; \ - a = ROT_N(a, 32); + b = ROTATE(b, s) ^ a; \ + d = ROTATE(d, t) ^ c; \ + a = ROTATE(a, 32); #define DOUBLE_ROUND(v0,v1,v2,v3) \ HALF_ROUND(v0,v1,v2,v3,13,16); \ From 8664bd7688876f4dd7ee2af98fecf54e656f5131 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 3 Apr 2021 21:32:59 -0700 Subject: [PATCH 20/47] Add docs for ROT_N --- Doc/library/dis.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index c21a667ba17112..9bc5046669a02e 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1248,6 +1248,14 @@ All of the following opcodes use their arguments. .. versionadded:: 3.10 +.. opcode:: ROT_N (count) + + Lift top *count* stack items one position up, and move TOS down to position + *count*. + + .. versionadded:: 3.10 + + .. opcode:: HAVE_ARGUMENT This is not really an opcode. It identifies the dividing line between From f72dc8712a854c1235ea6c27d9694d7d0b46768c Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 3 Apr 2021 21:34:25 -0700 Subject: [PATCH 21/47] Remove old comment --- Python/ceval.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/Python/ceval.c b/Python/ceval.c index 6c1675bed353e9..b569e386f6b202 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -4444,9 +4444,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) PyObject *top = TOP(); memmove(&PEEK(oparg - 1), &PEEK(oparg), sizeof(PyObject*) * (oparg - 1)); - // for (int i = 1; i < oparg; i++) { - // PEEK(i) = PEEK(i + 1); - // } PEEK(oparg) = top; DISPATCH(); } From 694bfb4578b5058b694de764c710712ccb0ac1f5 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 3 Apr 2021 22:10:37 -0700 Subject: [PATCH 22/47] Lots of cleanup and comments --- Python/compile.c | 132 ++++++++++++++++++++++++----------------------- 1 file changed, 68 insertions(+), 64 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 97ab0f205d52d3..cc092fa9131213 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -203,7 +203,10 @@ struct compiler { }; typedef struct { - // A list of strings corresponding to name captures. + // A list of strings corresponding to name captures. It is used to track: + // - Repeated name assignments in the same pattern. + // - Different name assignments in alternatives. + // - The order of name assignments in alternatives. PyObject *stores; // If 0, any name captures against our subject will raise. int allow_irrefutable; @@ -5489,9 +5492,16 @@ compiler_slice(struct compiler *c, expr_ty s) // PEP 634: Structural Pattern Matching -// To keep things simple, all compiler_pattern_* routines +// To keep things simple, all compiler_pattern_* and pattern_helper_* routines +// follow the convention of consuming TOS (the subject for the given pattern) +// and calling pattern_context_jump_to_fail_pop on failure (no match). + +// When calling into these routines, it's important that pc->on_top be kept +// updated to reflect the current number of items that we are using on the top +// of the stack: they will be popped on failure, and any name captures will be +// stored *underneath* them on success. This lets us defer all names stores +// until the *entire* pattern matches. -// TODO: this comment // TODO: other comments // TODO: check for memory leaks // TODO: variants of test_patma_282 with mappings, classes, stars, stores before/after @@ -5504,8 +5514,8 @@ compiler_slice(struct compiler *c, expr_ty s) // Allocate or resize pc->fail_pop to allow for n items to be popped on failure. static int -pattern_helper_ensure_fail_pop(struct compiler *c, pattern_context *pc, - Py_ssize_t n) +pattern_context_ensure_fail_pop(struct compiler *c, pattern_context *pc, + Py_ssize_t n) { Py_ssize_t size = n + 1; if (pc->fail_pop == NULL) { @@ -5534,13 +5544,13 @@ pattern_helper_ensure_fail_pop(struct compiler *c, pattern_context *pc, // Use op to jump to the correct fail_pop block. static int -pattern_helper_jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) +pattern_context_jump_to_fail_pop(struct compiler *c, pattern_context *pc, + int op) { - Py_ssize_t pops = pc->on_top; - if (pc->stores) { - pops += PyList_GET_SIZE(pc->stores); - } - RETURN_IF_FALSE(pattern_helper_ensure_fail_pop(c, pc, pops)); + // Pop any items on the top of the stack, plus any objects we were going to + // capture: + Py_ssize_t pops = pc->on_top + PyList_GET_SIZE(pc->stores); + RETURN_IF_FALSE(pattern_context_ensure_fail_pop(c, pc, pops)); ADDOP_JUMP(c, op, pc->fail_pop[pops]); NEXT_BLOCK(c); return 1; @@ -5549,7 +5559,7 @@ pattern_helper_jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) // Build all of the fail_pop blocks and free fail_pop. static int -pattern_helper_fail_pop_cleanup(struct compiler *c, pattern_context *pc) +pattern_context_fail_pop_cleanup(struct compiler *c, pattern_context *pc) { if (!pc->fail_pop_size) { goto done; @@ -5576,18 +5586,13 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) { assert(!_PyUnicode_EqualToASCIIString(n, "_")); // Can't assign to the same name twice: - if (pc->stores == NULL) { - RETURN_IF_FALSE(pc->stores = PyList_New(0)); + int duplicate = PySequence_Contains(pc->stores, n); + if (duplicate < 0) { + return 0; } - else { - int duplicate = PySequence_Contains(pc->stores, n); - if (duplicate < 0) { - return 0; - } - if (duplicate) { - const char *e = "multiple assignments to name %R in pattern"; - return compiler_error(c, e, n); - } + if (duplicate) { + const char *e = "multiple assignments to name %R in pattern"; + return compiler_error(c, e, n); } RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); // Rotate this object underneath any items we need to preserve: @@ -5625,6 +5630,8 @@ static int pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, Py_ssize_t star, pattern_context *pc) { + // We need to keep the subject around for extracting elements: + pc->on_top++; Py_ssize_t size = asdl_seq_LEN(values); for (Py_ssize_t i = 0; i < size; i++) { expr_ty value = asdl_seq_GET(values, i); @@ -5648,11 +5655,10 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, ADDOP(c, BINARY_SUBTRACT); } ADDOP(c, BINARY_SUBSCR); - pc->on_top++; RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); - pc->on_top--; - NEXT_BLOCK(c); } + // Pop the subject, we're done with it: + pc->on_top--; ADDOP(c, POP_TOP); return 1; } @@ -5675,11 +5681,11 @@ compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) { assert(p->kind == MatchAs_kind); // Need to make a copy for (possibly) storing later: - ADDOP(c, DUP_TOP); pc->on_top++; + ADDOP(c, DUP_TOP); RETURN_IF_FALSE(compiler_pattern(c, p->v.MatchAs.pattern, pc)); + // Success! Store it: pc->on_top--; - NEXT_BLOCK(c); RETURN_IF_FALSE(pattern_helper_store_name(c, p->v.MatchAs.name, pc)); return 1; } @@ -5724,10 +5730,9 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) } ADDOP_LOAD_CONST_NEW(c, kwnames); ADDOP_I(c, MATCH_CLASS, nargs); + // TOS is now a tuple of (nargs + nkwargs) attributes. Preserve them: pc->on_top++; - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->on_top--; - // TOS is now a tuple of (nargs + nkwargs) attributes. + RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); for (i = 0; i < nargs + nkwargs; i++) { expr_ty arg; if (i < nargs) { @@ -5745,12 +5750,10 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, DUP_TOP); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); - pc->on_top++; RETURN_IF_FALSE(compiler_pattern_subpattern(c, arg, pc)); - pc->on_top--; - NEXT_BLOCK(c); } // Success! Pop the tuple of attributes: + pc->on_top--; ADDOP(c, POP_TOP); return 1; } @@ -5765,7 +5768,7 @@ compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) // Literal True, False, and None are compared by identity. All others use // equality: ADDOP_COMPARE(c, (v == Py_None || PyBool_Check(v)) ? Is : Eq); - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); NEXT_BLOCK(c); return 1; } @@ -5781,7 +5784,7 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) int star = size ? !asdl_seq_GET(keys, size - 1) : 0; ADDOP(c, MATCH_MAPPING); pc->on_top++; - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->on_top--; if (!size) { // If the pattern is just "{}", we're done! @@ -5794,7 +5797,7 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - star)); ADDOP_COMPARE(c, GtE); pc->on_top++; - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->on_top--; } if (INT_MAX < size - star - 1) { @@ -5814,7 +5817,7 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_I(c, BUILD_TUPLE, size - star); ADDOP(c, MATCH_KEYS); pc->on_top += 3; - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->on_top -= 3; // So far so good. There's now a tuple of values on the stack to match // sub-patterns against: @@ -5863,8 +5866,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns); assert(size > 1); // We're going to be messing with pc. Keep the original info handy: - PyObject *stores_init; - RETURN_IF_FALSE(stores_init = pc->stores ? pc->stores : PyList_New(0)); + PyObject *stores_init = pc->stores; int allow_irrefutable = pc->allow_irrefutable; basicblock **fail_pop = pc->fail_pop; Py_ssize_t fail_pop_size = pc->fail_pop_size; @@ -5951,7 +5953,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) Py_DECREF(pc->stores); if (!compiler_addop_j(c, JUMP_FORWARD, end) || !compiler_next_block(c) || - (!is_last && !pattern_helper_fail_pop_cleanup(c, pc))) + (!is_last && !pattern_context_fail_pop_cleanup(c, pc))) { goto fail; } @@ -5973,6 +5975,8 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) static int compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) { + // We're keeping the subject around for the sequence and length checks: + pc->on_top++; assert(p->kind == List_kind || p->kind == Tuple_kind); asdl_expr_seq *values = (p->kind == Tuple_kind) ? p->v.Tuple.elts : p->v.List.elts; @@ -5994,23 +5998,23 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) } only_wildcard &= WILDCARD_CHECK(value); } - pc->on_top++; ADDOP(c, MATCH_SEQUENCE); - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); if (star < 0) { // No star: len(subject) == size ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size)); ADDOP_COMPARE(c, Eq); - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); } else if (size > 1) { // Star: len(subject) >= size - 1 ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - 1)); ADDOP_COMPARE(c, GtE); - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); } + // Whatever comes next should consume the subject: pc->on_top--; if (only_wildcard) { // Patterns like: [] / [_] / [_, _] / [*_] / [_, *_] / [_, _, *_] / etc. @@ -6033,7 +6037,7 @@ compiler_pattern_value(struct compiler *c, expr_ty p, pattern_context *pc) assert(p->v.Attribute.ctx == Load); VISIT(c, expr, p); ADDOP_COMPARE(c, Eq); - RETURN_IF_FALSE(pattern_helper_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); return 1; } @@ -6100,39 +6104,39 @@ compiler_match(struct compiler *c, stmt_ty s) Py_ssize_t cases = asdl_seq_LEN(s->v.Match.cases); assert(cases); pattern_context pc; - // We use pc.stores to track: - // - Repeated name assignments in the same pattern. - // - Different name assignments in alternatives. - // It's a list of names, but we don't create it until it's needed: pc.stores = NULL; match_case_ty m = asdl_seq_GET(s->v.Match.cases, cases - 1); int has_default = WILDCARD_CHECK(m->pattern) && 1 < cases; for (Py_ssize_t i = 0; i < cases - has_default; i++) { m = asdl_seq_GET(s->v.Match.cases, i); SET_LOC(c, m->pattern); + // Only copy the subject if we're *not* on the last case: + if (i != cases - has_default - 1) { + ADDOP(c, DUP_TOP); + } + RETURN_IF_FALSE(pc.stores = PyList_New(0)); // Irrefutable cases must be either guarded, last, or both: pc.allow_irrefutable = m->guard != NULL || i == cases - 1; pc.fail_pop = NULL; pc.fail_pop_size = 0; pc.on_top = 0; - // Only copy the subject if we're *not* on the last case: - if (i != cases - has_default - 1) { - ADDOP(c, DUP_TOP); - } int result = compiler_pattern(c, m->pattern, &pc); - RETURN_IF_FALSE(result); + if (!result) { + Py_DECREF(pc.stores); + return 0; + } assert(!pc.on_top); - NEXT_BLOCK(c); - if (pc.stores) { - Py_ssize_t i = PyList_GET_SIZE(pc.stores); - while (i--) { - PyObject *n = PyList_GET_ITEM(pc.stores, i); - RETURN_IF_FALSE(compiler_nameop(c, n, Store)); + Py_ssize_t nstores = PyList_GET_SIZE(pc.stores); + while (nstores--) { + PyObject *name = PyList_GET_ITEM(pc.stores, nstores); + if (!compiler_nameop(c, name, Store)) { + Py_DECREF(pc.stores); + return 0; } - Py_CLEAR(pc.stores); } + Py_DECREF(pc.stores); if (m->guard) { - RETURN_IF_FALSE(pattern_helper_ensure_fail_pop(c, &pc, 0)); + RETURN_IF_FALSE(pattern_context_ensure_fail_pop(c, &pc, 0)); RETURN_IF_FALSE(compiler_jump_if(c, m->guard, pc.fail_pop[0], 0)); } // Success! Pop the subject off, we're done with it: @@ -6141,7 +6145,7 @@ compiler_match(struct compiler *c, stmt_ty s) } VISIT_SEQ(c, stmt, m->body); ADDOP_JUMP(c, JUMP_FORWARD, end); - pattern_helper_fail_pop_cleanup(c, &pc); + pattern_context_fail_pop_cleanup(c, &pc); } if (has_default) { if (cases == 1) { From e4b49427cf4290d9f260b5dfe552f75e7a7b10bf Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 3 Apr 2021 22:32:21 -0700 Subject: [PATCH 23/47] Add proper error handling to compiler_match --- Python/compile.c | 82 +++++++++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index cc092fa9131213..045b1df5650c7c 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5511,7 +5511,7 @@ compiler_slice(struct compiler *c, expr_ty s) ((N)->kind == Name_kind && \ _PyUnicode_EqualToASCIIString((N)->v.Name.id, "_")) - +// TODO // Allocate or resize pc->fail_pop to allow for n items to be popped on failure. static int pattern_context_ensure_fail_pop(struct compiler *c, pattern_context *pc, @@ -5541,7 +5541,7 @@ pattern_context_ensure_fail_pop(struct compiler *c, pattern_context *pc, return 1; } - +// TODO // Use op to jump to the correct fail_pop block. static int pattern_context_jump_to_fail_pop(struct compiler *c, pattern_context *pc, @@ -5556,7 +5556,7 @@ pattern_context_jump_to_fail_pop(struct compiler *c, pattern_context *pc, return 1; } - +// TODO // Build all of the fail_pop blocks and free fail_pop. static int pattern_context_fail_pop_cleanup(struct compiler *c, pattern_context *pc) @@ -5580,7 +5580,7 @@ pattern_context_fail_pop_cleanup(struct compiler *c, pattern_context *pc) return 1; } - +// TODO static int pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) { @@ -5600,7 +5600,7 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) return 1; } - +// TODO static int pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, Py_ssize_t star, pattern_context *pc) @@ -5623,6 +5623,7 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, return 1; } +// TODO // Like pattern_helper_sequence_unpack, but uses BINARY_SUBSCR instead of // UNPACK_SEQUENCE / UNPACK_EX. This is more efficient for patterns with a // starred wildcard like [first, *_] / [first, *_, last] / [*_, last] / etc. @@ -5663,7 +5664,7 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, return 1; } - +// TODO // Like compiler_pattern, but turn off checks for irrefutability. static int compiler_pattern_subpattern(struct compiler *c, expr_ty p, pattern_context *pc) @@ -5675,7 +5676,7 @@ compiler_pattern_subpattern(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - +// TODO static int compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5690,7 +5691,7 @@ compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - +// TODO static int compiler_pattern_capture(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5706,7 +5707,7 @@ compiler_pattern_capture(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - +// TODO static int compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5758,7 +5759,7 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - +// TODO static int compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5773,7 +5774,7 @@ compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - +// TODO static int compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5852,7 +5853,7 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - +// TODO static int compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5971,7 +5972,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) return 0; } - +// TODO static int compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -6029,7 +6030,7 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - +// TODO static int compiler_pattern_value(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -6041,7 +6042,7 @@ compiler_pattern_value(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - +// TODO static int compiler_pattern_wildcard(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -6057,7 +6058,7 @@ compiler_pattern_wildcard(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } - +// TODO static int compiler_pattern(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -6094,17 +6095,15 @@ compiler_pattern(struct compiler *c, expr_ty p, pattern_context *pc) } } - +// TODO static int -compiler_match(struct compiler *c, stmt_ty s) +compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) { VISIT(c, expr, s->v.Match.subject); basicblock *end; RETURN_IF_FALSE(end = compiler_new_block(c)); Py_ssize_t cases = asdl_seq_LEN(s->v.Match.cases); assert(cases); - pattern_context pc; - pc.stores = NULL; match_case_ty m = asdl_seq_GET(s->v.Match.cases, cases - 1); int has_default = WILDCARD_CHECK(m->pattern) && 1 < cases; for (Py_ssize_t i = 0; i < cases - has_default; i++) { @@ -6114,30 +6113,31 @@ compiler_match(struct compiler *c, stmt_ty s) if (i != cases - has_default - 1) { ADDOP(c, DUP_TOP); } - RETURN_IF_FALSE(pc.stores = PyList_New(0)); + RETURN_IF_FALSE(pc->stores = PyList_New(0)); + // Can't use returning macros here (they'll leak pc->stores)! // Irrefutable cases must be either guarded, last, or both: - pc.allow_irrefutable = m->guard != NULL || i == cases - 1; - pc.fail_pop = NULL; - pc.fail_pop_size = 0; - pc.on_top = 0; - int result = compiler_pattern(c, m->pattern, &pc); - if (!result) { - Py_DECREF(pc.stores); + pc->allow_irrefutable = m->guard != NULL || i == cases - 1; + pc->fail_pop = NULL; + pc->fail_pop_size = 0; + pc->on_top = 0; + if (!compiler_pattern(c, m->pattern, pc)) { + Py_DECREF(pc->stores); return 0; } - assert(!pc.on_top); - Py_ssize_t nstores = PyList_GET_SIZE(pc.stores); + assert(!pc->on_top); + Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); while (nstores--) { - PyObject *name = PyList_GET_ITEM(pc.stores, nstores); + PyObject *name = PyList_GET_ITEM(pc->stores, nstores); if (!compiler_nameop(c, name, Store)) { - Py_DECREF(pc.stores); + Py_DECREF(pc->stores); return 0; } } - Py_DECREF(pc.stores); + Py_DECREF(pc->stores); + // Returning macros are safe again. if (m->guard) { - RETURN_IF_FALSE(pattern_context_ensure_fail_pop(c, &pc, 0)); - RETURN_IF_FALSE(compiler_jump_if(c, m->guard, pc.fail_pop[0], 0)); + RETURN_IF_FALSE(pattern_context_ensure_fail_pop(c, pc, 0)); + RETURN_IF_FALSE(compiler_jump_if(c, m->guard, pc->fail_pop[0], 0)); } // Success! Pop the subject off, we're done with it: if (i != cases - has_default - 1) { @@ -6145,7 +6145,7 @@ compiler_match(struct compiler *c, stmt_ty s) } VISIT_SEQ(c, stmt, m->body); ADDOP_JUMP(c, JUMP_FORWARD, end); - pattern_context_fail_pop_cleanup(c, &pc); + RETURN_IF_FALSE(pattern_context_fail_pop_cleanup(c, pc)); } if (has_default) { if (cases == 1) { @@ -6166,6 +6166,16 @@ compiler_match(struct compiler *c, stmt_ty s) } +static int +compiler_match(struct compiler *c, stmt_ty s) +{ + pattern_context pc; + int result = compiler_match_inner(c, s, &pc); + PyObject_Free(pc.fail_pop); + return result; +} + + #undef WILDCARD_CHECK From 37c324db3eaf42567c686c8a88d9098dce6c5b65 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sun, 4 Apr 2021 09:22:18 -0700 Subject: [PATCH 24/47] More cleanup --- Python/compile.c | 126 ++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 67 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 045b1df5650c7c..a3d6bd5640ad08 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5502,6 +5502,7 @@ compiler_slice(struct compiler *c, expr_ty s) // stored *underneath* them on success. This lets us defer all names stores // until the *entire* pattern matches. +// TODO: Routine names // TODO: other comments // TODO: check for memory leaks // TODO: variants of test_patma_282 with mappings, classes, stars, stores before/after @@ -5511,76 +5512,67 @@ compiler_slice(struct compiler *c, expr_ty s) ((N)->kind == Name_kind && \ _PyUnicode_EqualToASCIIString((N)->v.Name.id, "_")) -// TODO + // Allocate or resize pc->fail_pop to allow for n items to be popped on failure. static int -pattern_context_ensure_fail_pop(struct compiler *c, pattern_context *pc, - Py_ssize_t n) +ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n) { Py_ssize_t size = n + 1; - if (pc->fail_pop == NULL) { - pc->fail_pop = PyObject_Malloc(sizeof(basicblock*) * size); - if (pc->fail_pop == NULL) { - PyErr_NoMemory(); - return 0; - } + if (size <= pc->fail_pop_size) { + return 1; } - else if (pc->fail_pop_size < size) { - Py_ssize_t needed = sizeof(basicblock*) * size; - basicblock **new = PyObject_Realloc(pc->fail_pop, needed); - if (new == NULL) { - PyErr_NoMemory(); - return 0; - } - pc->fail_pop = new; + Py_ssize_t needed = sizeof(basicblock*) * size; + basicblock **resized = PyObject_Realloc(pc->fail_pop, needed); + if (resized == NULL) { + PyErr_NoMemory(); + return 0; } + pc->fail_pop = resized; while (pc->fail_pop_size < size) { - pc->fail_pop[pc->fail_pop_size] = compiler_new_block(c); - RETURN_IF_FALSE(pc->fail_pop[pc->fail_pop_size++]); + basicblock *new_block; + RETURN_IF_FALSE(new_block = compiler_new_block(c)); + pc->fail_pop[pc->fail_pop_size++] = new_block; } return 1; } -// TODO + // Use op to jump to the correct fail_pop block. static int -pattern_context_jump_to_fail_pop(struct compiler *c, pattern_context *pc, - int op) +jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) { // Pop any items on the top of the stack, plus any objects we were going to - // capture: + // capture on success: Py_ssize_t pops = pc->on_top + PyList_GET_SIZE(pc->stores); - RETURN_IF_FALSE(pattern_context_ensure_fail_pop(c, pc, pops)); + RETURN_IF_FALSE(ensure_fail_pop(c, pc, pops)); ADDOP_JUMP(c, op, pc->fail_pop[pops]); NEXT_BLOCK(c); return 1; } -// TODO -// Build all of the fail_pop blocks and free fail_pop. + +// Build all of the fail_pop blocks and reset fail_pop. static int -pattern_context_fail_pop_cleanup(struct compiler *c, pattern_context *pc) +cleanup_fail_pop(struct compiler *c, pattern_context *pc) { - if (!pc->fail_pop_size) { - goto done; - } - while (--pc->fail_pop_size) { - compiler_use_next_block(c, pc->fail_pop[pc->fail_pop_size]); - if (!compiler_addop(c, POP_TOP)) { - PyObject_Free(pc->fail_pop); - pc->fail_pop_size = 0; - pc->fail_pop = NULL; - return 0; + if (pc->fail_pop_size) { + while (--pc->fail_pop_size) { + compiler_use_next_block(c, pc->fail_pop[pc->fail_pop_size]); + if (!compiler_addop(c, POP_TOP)) { + PyObject_Free(pc->fail_pop); + pc->fail_pop_size = 0; + pc->fail_pop = NULL; + return 0; + } } + compiler_use_next_block(c, pc->fail_pop[0]); } - compiler_use_next_block(c, pc->fail_pop[0]); -done: PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; return 1; } -// TODO + static int pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) { @@ -5600,7 +5592,7 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) return 1; } -// TODO + static int pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, Py_ssize_t star, pattern_context *pc) @@ -5623,7 +5615,7 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_expr_seq *values, return 1; } -// TODO + // Like pattern_helper_sequence_unpack, but uses BINARY_SUBSCR instead of // UNPACK_SEQUENCE / UNPACK_EX. This is more efficient for patterns with a // starred wildcard like [first, *_] / [first, *_, last] / [*_, last] / etc. @@ -5664,7 +5656,7 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, return 1; } -// TODO + // Like compiler_pattern, but turn off checks for irrefutability. static int compiler_pattern_subpattern(struct compiler *c, expr_ty p, pattern_context *pc) @@ -5676,7 +5668,7 @@ compiler_pattern_subpattern(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } -// TODO + static int compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5691,7 +5683,7 @@ compiler_pattern_as(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } -// TODO + static int compiler_pattern_capture(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5707,7 +5699,7 @@ compiler_pattern_capture(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } -// TODO + static int compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5731,9 +5723,9 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) } ADDOP_LOAD_CONST_NEW(c, kwnames); ADDOP_I(c, MATCH_CLASS, nargs); - // TOS is now a tuple of (nargs + nkwargs) attributes. Preserve them: + // TOS is now a tuple of (nargs + nkwargs) attributes. Preserve it: pc->on_top++; - RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); for (i = 0; i < nargs + nkwargs; i++) { expr_ty arg; if (i < nargs) { @@ -5759,7 +5751,7 @@ compiler_pattern_class(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } -// TODO + static int compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5769,7 +5761,7 @@ compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) // Literal True, False, and None are compared by identity. All others use // equality: ADDOP_COMPARE(c, (v == Py_None || PyBool_Check(v)) ? Is : Eq); - RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); NEXT_BLOCK(c); return 1; } @@ -5785,7 +5777,7 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) int star = size ? !asdl_seq_GET(keys, size - 1) : 0; ADDOP(c, MATCH_MAPPING); pc->on_top++; - RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->on_top--; if (!size) { // If the pattern is just "{}", we're done! @@ -5798,7 +5790,7 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - star)); ADDOP_COMPARE(c, GtE); pc->on_top++; - RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->on_top--; } if (INT_MAX < size - star - 1) { @@ -5818,7 +5810,7 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP_I(c, BUILD_TUPLE, size - star); ADDOP(c, MATCH_KEYS); pc->on_top += 3; - RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); pc->on_top -= 3; // So far so good. There's now a tuple of values on the stack to match // sub-patterns against: @@ -5954,7 +5946,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) Py_DECREF(pc->stores); if (!compiler_addop_j(c, JUMP_FORWARD, end) || !compiler_next_block(c) || - (!is_last && !pattern_context_fail_pop_cleanup(c, pc))) + (!is_last && !cleanup_fail_pop(c, pc))) { goto fail; } @@ -5972,12 +5964,10 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) return 0; } -// TODO + static int compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) { - // We're keeping the subject around for the sequence and length checks: - pc->on_top++; assert(p->kind == List_kind || p->kind == Tuple_kind); asdl_expr_seq *values = (p->kind == Tuple_kind) ? p->v.Tuple.elts : p->v.List.elts; @@ -5999,21 +5989,23 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) } only_wildcard &= WILDCARD_CHECK(value); } + // Need to keep the subject on top during the sequence and length checks: + pc->on_top++; ADDOP(c, MATCH_SEQUENCE); - RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); if (star < 0) { // No star: len(subject) == size ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size)); ADDOP_COMPARE(c, Eq); - RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); } else if (size > 1) { // Star: len(subject) >= size - 1 ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - 1)); ADDOP_COMPARE(c, GtE); - RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); } // Whatever comes next should consume the subject: pc->on_top--; @@ -6030,7 +6022,7 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } -// TODO + static int compiler_pattern_value(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -6038,11 +6030,11 @@ compiler_pattern_value(struct compiler *c, expr_ty p, pattern_context *pc) assert(p->v.Attribute.ctx == Load); VISIT(c, expr, p); ADDOP_COMPARE(c, Eq); - RETURN_IF_FALSE(pattern_context_jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); return 1; } -// TODO + static int compiler_pattern_wildcard(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -6058,7 +6050,7 @@ compiler_pattern_wildcard(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } -// TODO + static int compiler_pattern(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -6114,12 +6106,12 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) ADDOP(c, DUP_TOP); } RETURN_IF_FALSE(pc->stores = PyList_New(0)); - // Can't use returning macros here (they'll leak pc->stores)! // Irrefutable cases must be either guarded, last, or both: pc->allow_irrefutable = m->guard != NULL || i == cases - 1; pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; + // Can't use returning macros here (they'll leak pc->stores)! if (!compiler_pattern(c, m->pattern, pc)) { Py_DECREF(pc->stores); return 0; @@ -6136,7 +6128,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) Py_DECREF(pc->stores); // Returning macros are safe again. if (m->guard) { - RETURN_IF_FALSE(pattern_context_ensure_fail_pop(c, pc, 0)); + RETURN_IF_FALSE(ensure_fail_pop(c, pc, 0)); RETURN_IF_FALSE(compiler_jump_if(c, m->guard, pc->fail_pop[0], 0)); } // Success! Pop the subject off, we're done with it: @@ -6145,7 +6137,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) } VISIT_SEQ(c, stmt, m->body); ADDOP_JUMP(c, JUMP_FORWARD, end); - RETURN_IF_FALSE(pattern_context_fail_pop_cleanup(c, pc)); + RETURN_IF_FALSE(cleanup_fail_pop(c, pc)); } if (has_default) { if (cases == 1) { From 85ee8c910a168c1ccda53c1da53bb8c4973b9d3f Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sun, 4 Apr 2021 10:38:14 -0700 Subject: [PATCH 25/47] WIP on cleaning up name handling in alternatives --- Lib/test/test_patma.py | 9 ++++ Python/compile.c | 115 +++++++++++++++++++---------------------- 2 files changed, 63 insertions(+), 61 deletions(-) diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index 5b5c2494133021..3c011b119a9da0 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2842,6 +2842,15 @@ def test_patma_281(self): self.assertIs(y, None) def test_patma_282(self): + x = {"y": 1} + match x: + case {"y": (0 as y) | (1 as y)}: + z = 0 + self.assertEqual(x, {"y": 1}) + self.assertEqual(y, 1) + self.assertEqual(z, 0) + + def test_patma_283(self): def f(x): match x: case ((a, b, c, d, e, f, g, h, i, 9) | diff --git a/Python/compile.c b/Python/compile.c index a3d6bd5640ad08..fa625275eddd48 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5503,9 +5503,7 @@ compiler_slice(struct compiler *c, expr_ty s) // until the *entire* pattern matches. // TODO: Routine names -// TODO: other comments -// TODO: check for memory leaks -// TODO: variants of test_patma_282 with mappings, classes, stars, stores before/after +// TODO: variants of test_patma_283 with mappings, classes, stars, stores before/after #define WILDCARD_CHECK(N) \ @@ -5847,68 +5845,58 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) // TODO static int -compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) +pattern_helper_or(struct compiler *c, expr_ty p, pattern_context *pc) { assert(p->kind == MatchOr_kind); - // control is the list of names bound by the first alternative. If all of - // the others bind the same names (they should), then this becomes - // pc->stores. - PyObject *control = NULL; + // control will be is the list of names bound by the first alternative. If + // all of the others bind the same names (they should), then it becomes the + // new pc->stores. basicblock *end; RETURN_IF_FALSE(end = compiler_new_block(c)); Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns); assert(size > 1); // We're going to be messing with pc. Keep the original info handy: - PyObject *stores_init = pc->stores; - int allow_irrefutable = pc->allow_irrefutable; - basicblock **fail_pop = pc->fail_pop; - Py_ssize_t fail_pop_size = pc->fail_pop_size; - Py_ssize_t on_top = pc->on_top; - Py_ssize_t nstores_init = PyList_GET_SIZE(stores_init); + pattern_context subpc = *pc; + Py_ssize_t nstores_init = PyList_GET_SIZE(pc->stores); Py_ssize_t ncontrol = 0; for (Py_ssize_t i = 0; i < size; i++) { // NOTE: Can't use our nice returning macros here: they'll leak lists! expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); // An irrefutable sub-pattern must be last, if it is allowed at all: int is_last = i == size - 1; - pc->stores = PySequence_List(stores_init); SET_LOC(c, alt); if (is_last) { - pc->allow_irrefutable = allow_irrefutable; - pc->fail_pop = fail_pop; - pc->fail_pop_size = fail_pop_size; - pc->on_top = on_top; + subpc = *pc; } else { - pc->allow_irrefutable = 0; - pc->fail_pop = NULL; - pc->fail_pop_size = 0; - pc->on_top = 0; - } - if (pc->stores == NULL || - // Only copy the subject if we're *not* on the last alternative: - (!is_last && !compiler_addop(c, DUP_TOP)) || - !compiler_pattern(c, alt, pc)) - { - goto fail; + subpc.allow_irrefutable = 0; + subpc.fail_pop = NULL; + subpc.fail_pop_size = 0; + subpc.on_top = 0; } - Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); + RETURN_IF_FALSE(subpc.stores = PyList_GetSlice(pc->stores, 0, nstores_init)); + // Only copy the subject if we're *not* on the last alternative: + if (!is_last) { + ADDOP(c, DUP_TOP); + } + if (!compiler_pattern(c, alt, &subpc)) { + Py_DECREF(subpc.stores); + return 0; + } + Py_ssize_t nstores = PyList_GET_SIZE(subpc.stores); if (!is_last) { for (Py_ssize_t i = 0; i < nstores - nstores_init; i++) { - if (!compiler_addop_i(c, ROT_N, nstores - nstores_init + 1)) { - goto fail; - } - } - if (!compiler_addop(c, POP_TOP)) { - goto fail; + ADDOP_I(c, ROT_N, nstores - nstores_init + 1); } + ADDOP(c, POP_TOP); } if (!i) { // If this is the first alternative, save its stores as a "control" // for the others (they can't bind a different set of names): - control = pc->stores; + Py_DECREF(pc->stores); + pc->stores = subpc.stores; + Py_INCREF(pc->stores); ncontrol = nstores; - Py_INCREF(control); } else if (nstores != ncontrol) { goto diff; @@ -5916,8 +5904,8 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) else if (nstores_init < nstores) { // Otherwise, check to see if we differ from the control list: for (Py_ssize_t j = nstores_init; j < nstores; j++) { - PyObject *name = PyList_GET_ITEM(control, j); - Py_ssize_t k = PySequence_Index(pc->stores, name); + PyObject *name = PyList_GET_ITEM(pc->stores, j); + Py_ssize_t k = PySequence_Index(subpc.stores, name); if (k < 0) { PyErr_Clear(); goto diff; @@ -5928,14 +5916,14 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // orders, but it's fine for reasonable cases. There's probably // a better way of doing this, though. assert(j <= k); - // Perfom the same rotation on pc->stores: - PyObject *rotate = PyList_GetSlice(pc->stores, k, nstores); + // Perfom the same rotation on subpc.stores: + PyObject *rotate = PyList_GetSlice(subpc.stores, k, nstores); if (rotate == NULL || - PyList_SetSlice(pc->stores, k, nstores, NULL) || - PyList_SetSlice(pc->stores, j, j, rotate)) + PyList_SetSlice(subpc.stores, k, nstores, NULL) || + PyList_SetSlice(subpc.stores, j, j, rotate)) { Py_XDECREF(rotate); - goto fail; + return 0; } Py_DECREF(rotate); while (k++ < ncontrol) { @@ -5943,28 +5931,31 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) } } } - Py_DECREF(pc->stores); - if (!compiler_addop_j(c, JUMP_FORWARD, end) || - !compiler_next_block(c) || - (!is_last && !cleanup_fail_pop(c, pc))) - { - goto fail; + ADDOP_JUMP(c, JUMP_FORWARD, end); + NEXT_BLOCK(c); + if (!is_last) { + RETURN_IF_FALSE(cleanup_fail_pop(c, &subpc)); + Py_DECREF(subpc.stores); } } - Py_XDECREF(stores_init); - // Update pc->stores and restore pc->allow_irrefutable: - pc->stores = control; + *pc = subpc; compiler_use_next_block(c, end); return 1; diff: + Py_DECREF(subpc.stores); compiler_error(c, "alternative patterns bind different names"); -fail: - Py_XDECREF(stores_init); - Py_XDECREF(control); return 0; } +static int +compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) +{ + int result = pattern_helper_or(c, p, pc); + return result; +} + + static int compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -6087,7 +6078,7 @@ compiler_pattern(struct compiler *c, expr_ty p, pattern_context *pc) } } -// TODO + static int compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) { @@ -6111,12 +6102,14 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - // Can't use returning macros here (they'll leak pc->stores)! + // NOTE: Can't use returning macros here (they'll leak pc->stores)! if (!compiler_pattern(c, m->pattern, pc)) { Py_DECREF(pc->stores); return 0; } assert(!pc->on_top); + // It's a match! Store all of the captured names (they're on the stack + // in reverse order). Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); while (nstores--) { PyObject *name = PyList_GET_ITEM(pc->stores, nstores); @@ -6126,7 +6119,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) } } Py_DECREF(pc->stores); - // Returning macros are safe again. + // NOTE: Returning macros are safe again. if (m->guard) { RETURN_IF_FALSE(ensure_fail_pop(c, pc, 0)); RETURN_IF_FALSE(compiler_jump_if(c, m->guard, pc->fail_pop[0], 0)); From e6f234c2fb0d1240e529a4209f3da28a8a636d5d Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sun, 4 Apr 2021 12:05:58 -0700 Subject: [PATCH 26/47] Clean up compiler_pattern_mapping --- Python/compile.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index fa625275eddd48..13b33f9bba2d58 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5764,7 +5764,7 @@ compiler_pattern_literal(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } -// TODO + static int compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) { @@ -5773,12 +5773,13 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) Py_ssize_t size = asdl_seq_LEN(values); // A starred pattern will be a keyless value. It is guaranteed to be last: int star = size ? !asdl_seq_GET(keys, size - 1) : 0; - ADDOP(c, MATCH_MAPPING); + // We need to keep the subject on top during the mapping and length checks: pc->on_top++; + ADDOP(c, MATCH_MAPPING); RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->on_top--; if (!size) { - // If the pattern is just "{}", we're done! + // If the pattern is just "{}", we're done! Pop the subject: + pc->on_top--; ADDOP(c, POP_TOP); return 1; } @@ -5787,9 +5788,7 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, GET_LEN); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(size - star)); ADDOP_COMPARE(c, GtE); - pc->on_top++; RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->on_top--; } if (INT_MAX < size - star - 1) { return compiler_error(c, "too many sub-patterns in mapping pattern"); @@ -5807,10 +5806,10 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) } ADDOP_I(c, BUILD_TUPLE, size - star); ADDOP(c, MATCH_KEYS); - pc->on_top += 3; + // There's now a tuple of keys and a tuple of values on top of the subject: + pc->on_top += 2; RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); - pc->on_top -= 3; - // So far so good. There's now a tuple of values on the stack to match + // So far so good. Use that tuple of values on the stack to match // sub-patterns against: for (Py_ssize_t i = 0; i < size - star; i++) { expr_ty value = asdl_seq_GET(values, i); @@ -5820,25 +5819,24 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) ADDOP(c, DUP_TOP); ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); ADDOP(c, BINARY_SUBSCR); - pc->on_top += 3; RETURN_IF_FALSE(compiler_pattern_subpattern(c, value, pc)); - pc->on_top -= 3; } - // If we get this far, it's a match! We're done with that tuple of values. + // If we get this far, it's a match! We're done with the tuple of values, + // and whatever happens next should consume the tuple of keys underneath it: + pc->on_top -= 2; ADDOP(c, POP_TOP); if (star) { // If we had a starred name, bind a dict of remaining items to it: ADDOP(c, COPY_DICT_WITHOUT_KEYS); PyObject *id = asdl_seq_GET(values, size - 1)->v.Name.id; - pc->on_top++; RETURN_IF_FALSE(pattern_helper_store_name(c, id, pc)); - pc->on_top--; } else { // Otherwise, we don't care about this tuple of keys anymore: ADDOP(c, POP_TOP); } // Pop the subject: + pc->on_top--; ADDOP(c, POP_TOP); return 1; } @@ -5848,9 +5846,6 @@ static int pattern_helper_or(struct compiler *c, expr_ty p, pattern_context *pc) { assert(p->kind == MatchOr_kind); - // control will be is the list of names bound by the first alternative. If - // all of the others bind the same names (they should), then it becomes the - // new pc->stores. basicblock *end; RETURN_IF_FALSE(end = compiler_new_block(c)); Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns); @@ -5866,6 +5861,8 @@ pattern_helper_or(struct compiler *c, expr_ty p, pattern_context *pc) int is_last = i == size - 1; SET_LOC(c, alt); if (is_last) { + // For the last alternative, control flow is basically "back to + // normal". So just use pc. subpc = *pc; } else { @@ -5980,7 +5977,7 @@ compiler_pattern_sequence(struct compiler *c, expr_ty p, pattern_context *pc) } only_wildcard &= WILDCARD_CHECK(value); } - // Need to keep the subject on top during the sequence and length checks: + // We need to keep the subject on top during the sequence and length checks: pc->on_top++; ADDOP(c, MATCH_SEQUENCE); RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); From 2c5c447e255f7a37137967a8ac9f5ad191944636 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 5 Apr 2021 11:42:13 -0700 Subject: [PATCH 27/47] *Finally* figure out why -R runs weren't failing --- Lib/test/test_patma.py | 15 +++ Python/compile.c | 204 +++++++++++++++++++++++------------------ 2 files changed, 131 insertions(+), 88 deletions(-) diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index 3c011b119a9da0..ca9f04eacffd03 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2874,6 +2874,21 @@ def f(x): self.assertEqual(f(range(-1, -11, -1)), alts[3]) self.assertEqual(f(range(10, 20)), alts[4]) + def test_patma_284(self): + self.assert_syntax_error(""" + match ...: + case [a, [b] | [c] | [d]]: + pass + """) + + @no_perf + def test_patma_285(self): + # Hunting for refleaks using -R doesn't catch refleaks in the compiler, + # just the code under test. This test ensures that if the pattern + # compiler is leaky, those runs will fail: + with open(__file__) as file: + compile(file.read(), __file__, "exec") + class PerfPatma(TestPatma): diff --git a/Python/compile.c b/Python/compile.c index 13b33f9bba2d58..21225329adaa66 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5655,6 +5655,86 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, } +static int +pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, + PyObject **control, Py_ssize_t old_nstores, + pattern_context *pc) +{ + // Only copy the subject if we're *not* on the last alternative: + if (!is_last) { + ADDOP(c, DUP_TOP); + } + RETURN_IF_FALSE(compiler_pattern(c, p, pc)); + Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); + // Success! + if (!is_last) { + // The duplicate copy of the subject is under the new names. Rotate it + // back to the top and pop it off. This could probably be improved by + // using a single "UNROT_N" instruction instead of lots of ROT_N ones: + for (Py_ssize_t i = 0; i < nstores - old_nstores; i++) { + ADDOP_I(c, ROT_N, nstores - old_nstores + 1); + } + ADDOP(c, POP_TOP); + } + if (*control == NULL) { + // This is the first alternative, so save its stores as a "control" for + // the others (they can't bind a different set of names, and might need + // to be reordered): + *control = pc->stores; + Py_INCREF(*control); + } + else if (nstores != PyList_GET_SIZE(*control)) { + goto diff; + } + else if (old_nstores < nstores) { + // There were captures. Check to see if we differ from the control list: + for (Py_ssize_t icontrol = old_nstores; icontrol < nstores; icontrol++) + { + PyObject *name = PyList_GET_ITEM(*control, icontrol); + Py_ssize_t istores = PySequence_Index(pc->stores, name); + if (istores < 0) { + PyErr_Clear(); + goto diff; + } + // Reorder the names on the stack to match the order of the names in + // control. There's probably a better way of doing this; the current + // solution is potentially very inefficient when each alternative + // subpattern binds lots of names in different orders. It's fine for + // reasonable cases, though. + assert(icontrol <= istores); + // Perfom the same rotation on pc->stores: + PyObject *rotate = PyList_GetSlice(pc->stores, istores, nstores); + if (rotate == NULL || + PyList_SetSlice(pc->stores, istores, nstores, NULL) || + PyList_SetSlice(pc->stores, icontrol, icontrol, rotate)) + { + Py_XDECREF(rotate); + return 0; + } + Py_DECREF(rotate); + // That just did: + // rotate = pc_stores[istores:] + // del pc_stores[istores:] + // pc_stores[icontrol:icontrol] = rotate + // Do the exact same thing to the stack, using several rotations: + while (istores++ < nstores) { + ADDOP_I(c, ROT_N, nstores - icontrol); + } + } + } + ADDOP_JUMP(c, JUMP_FORWARD, end); + NEXT_BLOCK(c); + if (!is_last) { + // All alternatives (except the last one) jump here on failure: + RETURN_IF_FALSE(cleanup_fail_pop(c, pc)); + } + return 1; +diff: + compiler_error(c, "alternative patterns bind different names"); + return 0; +} + + // Like compiler_pattern, but turn off checks for irrefutability. static int compiler_pattern_subpattern(struct compiler *c, expr_ty p, pattern_context *pc) @@ -5841,9 +5921,9 @@ compiler_pattern_mapping(struct compiler *c, expr_ty p, pattern_context *pc) return 1; } -// TODO + static int -pattern_helper_or(struct compiler *c, expr_ty p, pattern_context *pc) +compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) { assert(p->kind == MatchOr_kind); basicblock *end; @@ -5851,105 +5931,53 @@ pattern_helper_or(struct compiler *c, expr_ty p, pattern_context *pc) Py_ssize_t size = asdl_seq_LEN(p->v.MatchOr.patterns); assert(size > 1); // We're going to be messing with pc. Keep the original info handy: - pattern_context subpc = *pc; - Py_ssize_t nstores_init = PyList_GET_SIZE(pc->stores); - Py_ssize_t ncontrol = 0; + pattern_context old_pc = *pc; + Py_INCREF(pc->stores); + Py_ssize_t old_nstores = PyList_GET_SIZE(pc->stores); + // control is the list of names bound by the first alternative. It is used + // for checking different name bindings in alternatives, and for correcting + // the order in which extracted elements are placed on the stack. + PyObject *control = NULL; for (Py_ssize_t i = 0; i < size; i++) { - // NOTE: Can't use our nice returning macros here: they'll leak lists! expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); - // An irrefutable sub-pattern must be last, if it is allowed at all: - int is_last = i == size - 1; SET_LOC(c, alt); + int is_last = i == size - 1; if (is_last) { - // For the last alternative, control flow is basically "back to - // normal". So just use pc. - subpc = *pc; + // For the last alternative, all control flow is basically "back to + // normal". Just use old_pc. + Py_DECREF(pc->stores); + *pc = old_pc; + Py_INCREF(pc->stores); } else { - subpc.allow_irrefutable = 0; - subpc.fail_pop = NULL; - subpc.fail_pop_size = 0; - subpc.on_top = 0; - } - RETURN_IF_FALSE(subpc.stores = PyList_GetSlice(pc->stores, 0, nstores_init)); - // Only copy the subject if we're *not* on the last alternative: - if (!is_last) { - ADDOP(c, DUP_TOP); - } - if (!compiler_pattern(c, alt, &subpc)) { - Py_DECREF(subpc.stores); - return 0; - } - Py_ssize_t nstores = PyList_GET_SIZE(subpc.stores); - if (!is_last) { - for (Py_ssize_t i = 0; i < nstores - nstores_init; i++) { - ADDOP_I(c, ROT_N, nstores - nstores_init + 1); + // Set up a "fresh" pc containing only a copy of prior stores: + PyObject *pc_stores = PySequence_List(old_pc.stores); + if (pc_stores == NULL) { + Py_DECREF(old_pc.stores); + Py_XDECREF(control); + return 0; } - ADDOP(c, POP_TOP); + Py_SETREF(pc->stores, pc_stores); + pc->allow_irrefutable = 0; + pc->fail_pop = NULL; + pc->fail_pop_size = 0; + pc->on_top = 0; } - if (!i) { - // If this is the first alternative, save its stores as a "control" - // for the others (they can't bind a different set of names): - Py_DECREF(pc->stores); - pc->stores = subpc.stores; - Py_INCREF(pc->stores); - ncontrol = nstores; - } - else if (nstores != ncontrol) { - goto diff; - } - else if (nstores_init < nstores) { - // Otherwise, check to see if we differ from the control list: - for (Py_ssize_t j = nstores_init; j < nstores; j++) { - PyObject *name = PyList_GET_ITEM(pc->stores, j); - Py_ssize_t k = PySequence_Index(subpc.stores, name); - if (k < 0) { - PyErr_Clear(); - goto diff; - } - // Reorder the names on the stack to match the order of the - // names in control. This is potentially very inefficient when - // each alternative subpattern binds lots of names in different - // orders, but it's fine for reasonable cases. There's probably - // a better way of doing this, though. - assert(j <= k); - // Perfom the same rotation on subpc.stores: - PyObject *rotate = PyList_GetSlice(subpc.stores, k, nstores); - if (rotate == NULL || - PyList_SetSlice(subpc.stores, k, nstores, NULL) || - PyList_SetSlice(subpc.stores, j, j, rotate)) - { - Py_XDECREF(rotate); - return 0; - } - Py_DECREF(rotate); - while (k++ < ncontrol) { - ADDOP_I(c, ROT_N, ncontrol - j); - } + if (!pattern_helper_or(c, alt, end, is_last, &control, old_nstores, pc)) + { + if (!is_last) { + PyObject_Free(old_pc.fail_pop); } + Py_DECREF(old_pc.stores); + Py_XDECREF(control); + return 0; } - ADDOP_JUMP(c, JUMP_FORWARD, end); - NEXT_BLOCK(c); - if (!is_last) { - RETURN_IF_FALSE(cleanup_fail_pop(c, &subpc)); - Py_DECREF(subpc.stores); - } + assert(control); } - *pc = subpc; + Py_DECREF(old_pc.stores); + Py_DECREF(control); compiler_use_next_block(c, end); return 1; -diff: - Py_DECREF(subpc.stores); - compiler_error(c, "alternative patterns bind different names"); - return 0; -} - - -static int -compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) -{ - int result = pattern_helper_or(c, p, pc); - return result; } From 465c1761b26a1357d8ffc835ab4bbada40416ca5 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 5 Apr 2021 14:41:36 -0700 Subject: [PATCH 28/47] Get nested alternatives working better --- Lib/test/test_patma.py | 54 ++++++++++++++++++++++++++++++------------ Python/compile.c | 29 ++++++++++++++--------- 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index ca9f04eacffd03..68848ea6e96ec7 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2851,21 +2851,28 @@ def test_patma_282(self): self.assertEqual(z, 0) def test_patma_283(self): + self.assert_syntax_error(""" + match ...: + case [a, [b] | [c] | [d]]: + pass + """) + + def test_patma_284(self): def f(x): match x: case ((a, b, c, d, e, f, g, h, i, 9) | (h, g, i, a, b, d, e, c, f, 10) | (g, b, a, c, d, -5, e, h, i, f) | (-1, d, f, b, g, e, i, a, h, c)): - pass + w = 0 out = locals() del out["x"] return out alts = [ - dict(a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7, i=8), - dict(h=1, g=2, i=3, a=4, b=5, d=6, e=7, c=8, f=9), - dict(g=0, b=-1, a=-2, c=-3, d=-4, e=-6, h=-7, i=-8, f=-9), - dict(d=-2, f=-3, b=-4, g=-5, e=-6, i=-7, a=-8, h=-9, c=-10), + dict(a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7, i=8, w=0), + dict(h=1, g=2, i=3, a=4, b=5, d=6, e=7, c=8, f=9, w=0), + dict(g=0, b=-1, a=-2, c=-3, d=-4, e=-6, h=-7, i=-8, f=-9, w=0), + dict(d=-2, f=-3, b=-4, g=-5, e=-6, i=-7, a=-8, h=-9, c=-10, w=0), dict(), ] self.assertEqual(f(range(10)), alts[0]) @@ -2874,18 +2881,35 @@ def f(x): self.assertEqual(f(range(-1, -11, -1)), alts[3]) self.assertEqual(f(range(10, 20)), alts[4]) - def test_patma_284(self): - self.assert_syntax_error(""" - match ...: - case [a, [b] | [c] | [d]]: - pass - """) + def test_patma_285(self): + def f(x): + match x: + case [y, (a, b, c, d, e, f, g, h, i, 9) | + (h, g, i, a, b, d, e, c, f, 10) | + (g, b, a, c, d, -5, e, h, i, f) | + (-1, d, f, b, g, e, i, a, h, c), z]: + w = 0 + out = locals() + del out["x"] + return out + alts = [ + dict(a=0, b=1, c=2, d=3, e=4, f=5, g=6, h=7, i=8, w=0, y=False, z=True), + dict(h=1, g=2, i=3, a=4, b=5, d=6, e=7, c=8, f=9, w=0, y=False, z=True), + dict(g=0, b=-1, a=-2, c=-3, d=-4, e=-6, h=-7, i=-8, f=-9, w=0, y=False, z=True), + dict(d=-2, f=-3, b=-4, g=-5, e=-6, i=-7, a=-8, h=-9, c=-10, w=0, y=False, z=True), + dict(), + ] + self.assertEqual(f((False, range(10), True)), alts[0]) + self.assertEqual(f((False, range(1, 11), True)), alts[1]) + self.assertEqual(f((False, range(0, -10, -1), True)), alts[2]) + self.assertEqual(f((False, range(-1, -11, -1), True)), alts[3]) + self.assertEqual(f((False, range(10, 20), True)), alts[4]) @no_perf - def test_patma_285(self): - # Hunting for refleaks using -R doesn't catch refleaks in the compiler, - # just the code under test. This test ensures that if the pattern - # compiler is leaky, those runs will fail: + def test_patma_286(self): + # Hunting for leaks using -R doesn't catch leaks in the compiler itself, + # just the code under test. This test ensures that if there are leaks in + # the pattern compiler, those runs will fail: with open(__file__) as file: compile(file.read(), __file__, "exec") diff --git a/Python/compile.c b/Python/compile.c index 21225329adaa66..7670dbd63c3429 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -225,6 +225,7 @@ typedef struct { // stack. Variable captures go beneath these. All of them will be popped on // failure. Py_ssize_t on_top; + Py_ssize_t adj; } pattern_context; static int compiler_enter_scope(struct compiler *, identifier, int, void *, int); @@ -5502,7 +5503,6 @@ compiler_slice(struct compiler *c, expr_ty s) // stored *underneath* them on success. This lets us defer all names stores // until the *entire* pattern matches. -// TODO: Routine names // TODO: variants of test_patma_283 with mappings, classes, stars, stores before/after @@ -5541,7 +5541,7 @@ jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) { // Pop any items on the top of the stack, plus any objects we were going to // capture on success: - Py_ssize_t pops = pc->on_top + PyList_GET_SIZE(pc->stores); + Py_ssize_t pops = pc->on_top + PyList_GET_SIZE(pc->stores) + pc->adj; RETURN_IF_FALSE(ensure_fail_pop(c, pc, pops)); ADDOP_JUMP(c, op, pc->fail_pop[pops]); NEXT_BLOCK(c); @@ -5657,8 +5657,7 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, static int pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, - PyObject **control, Py_ssize_t old_nstores, - pattern_context *pc) + PyObject **control, Py_ssize_t on_top, pattern_context *pc) { // Only copy the subject if we're *not* on the last alternative: if (!is_last) { @@ -5671,8 +5670,8 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, // The duplicate copy of the subject is under the new names. Rotate it // back to the top and pop it off. This could probably be improved by // using a single "UNROT_N" instruction instead of lots of ROT_N ones: - for (Py_ssize_t i = 0; i < nstores - old_nstores; i++) { - ADDOP_I(c, ROT_N, nstores - old_nstores + 1); + for (Py_ssize_t i = 0; i < nstores + pc->adj; i++) { + ADDOP_I(c, ROT_N, nstores + pc->adj + on_top + 1); } ADDOP(c, POP_TOP); } @@ -5686,9 +5685,12 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, else if (nstores != PyList_GET_SIZE(*control)) { goto diff; } - else if (old_nstores < nstores) { + else if (-pc->adj < nstores) { + for (Py_ssize_t i = 0; i < on_top; i++) { + ADDOP_I(c, ROT_N, nstores + pc->adj + on_top); + } // There were captures. Check to see if we differ from the control list: - for (Py_ssize_t icontrol = old_nstores; icontrol < nstores; icontrol++) + for (Py_ssize_t icontrol = -pc->adj; icontrol < nstores; icontrol++) { PyObject *name = PyList_GET_ITEM(*control, icontrol); Py_ssize_t istores = PySequence_Index(pc->stores, name); @@ -5721,11 +5723,13 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, ADDOP_I(c, ROT_N, nstores - icontrol); } } + for (Py_ssize_t i = 0; i < nstores + pc->adj; i++) { + ADDOP_I(c, ROT_N, nstores + pc->adj + on_top); + } } ADDOP_JUMP(c, JUMP_FORWARD, end); NEXT_BLOCK(c); if (!is_last) { - // All alternatives (except the last one) jump here on failure: RETURN_IF_FALSE(cleanup_fail_pop(c, pc)); } return 1; @@ -5962,9 +5966,9 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; + pc->adj = -old_nstores; } - if (!pattern_helper_or(c, alt, end, is_last, &control, old_nstores, pc)) - { + if (!pattern_helper_or(c, alt, end, is_last, &control, old_pc.on_top, pc)) { if (!is_last) { PyObject_Free(old_pc.fail_pop); } @@ -6071,6 +6075,7 @@ static int compiler_pattern(struct compiler *c, expr_ty p, pattern_context *pc) { SET_LOC(c, p); + int res; switch (p->kind) { case Attribute_kind: return compiler_pattern_value(c, p, pc); @@ -6101,6 +6106,7 @@ compiler_pattern(struct compiler *c, expr_ty p, pattern_context *pc) default: Py_UNREACHABLE(); } + return res; } @@ -6127,6 +6133,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; + pc->adj = 0; // NOTE: Can't use returning macros here (they'll leak pc->stores)! if (!compiler_pattern(c, m->pattern, pc)) { Py_DECREF(pc->stores); From 942c45833010cd851aa124f39ca0e6d49291faca Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 5 Apr 2021 14:56:33 -0700 Subject: [PATCH 29/47] Improve efficiency of alternatives --- Python/compile.c | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 7670dbd63c3429..da02025951fffb 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5666,15 +5666,6 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, RETURN_IF_FALSE(compiler_pattern(c, p, pc)); Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); // Success! - if (!is_last) { - // The duplicate copy of the subject is under the new names. Rotate it - // back to the top and pop it off. This could probably be improved by - // using a single "UNROT_N" instruction instead of lots of ROT_N ones: - for (Py_ssize_t i = 0; i < nstores + pc->adj; i++) { - ADDOP_I(c, ROT_N, nstores + pc->adj + on_top + 1); - } - ADDOP(c, POP_TOP); - } if (*control == NULL) { // This is the first alternative, so save its stores as a "control" for // the others (they can't bind a different set of names, and might need @@ -5686,10 +5677,12 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, goto diff; } else if (-pc->adj < nstores) { - for (Py_ssize_t i = 0; i < on_top; i++) { - ADDOP_I(c, ROT_N, nstores + pc->adj + on_top); - } // There were captures. Check to see if we differ from the control list: + if (is_last) { + for (Py_ssize_t i = 0; i < pc->on_top; i++) { + ADDOP_I(c, ROT_N, nstores + pc->adj + pc->on_top); + } + } for (Py_ssize_t icontrol = -pc->adj; icontrol < nstores; icontrol++) { PyObject *name = PyList_GET_ITEM(*control, icontrol); @@ -5723,9 +5716,14 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, ADDOP_I(c, ROT_N, nstores - icontrol); } } - for (Py_ssize_t i = 0; i < nstores + pc->adj; i++) { - ADDOP_I(c, ROT_N, nstores + pc->adj + on_top); - } + } + // The duplicate copy of the subject is under the new names. Rotate it + // back to the top and pop it off. + for (Py_ssize_t i = 0; i < nstores + pc->adj; i++) { + ADDOP_I(c, ROT_N, nstores + pc->adj + on_top + !is_last); + } + if (!is_last) { + ADDOP(c, POP_TOP); } ADDOP_JUMP(c, JUMP_FORWARD, end); NEXT_BLOCK(c); From e791f853463275f3326d3122ecd0ec9351c9f96a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 5 Apr 2021 15:58:39 -0700 Subject: [PATCH 30/47] Ditch pc->adj --- Python/compile.c | 92 ++++++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index da02025951fffb..6e990082883b5e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -225,7 +225,6 @@ typedef struct { // stack. Variable captures go beneath these. All of them will be popped on // failure. Py_ssize_t on_top; - Py_ssize_t adj; } pattern_context; static int compiler_enter_scope(struct compiler *, identifier, int, void *, int); @@ -5541,7 +5540,7 @@ jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) { // Pop any items on the top of the stack, plus any objects we were going to // capture on success: - Py_ssize_t pops = pc->on_top + PyList_GET_SIZE(pc->stores) + pc->adj; + Py_ssize_t pops = pc->on_top + PyList_GET_SIZE(pc->stores); RETURN_IF_FALSE(ensure_fail_pop(c, pc, pops)); ADDOP_JUMP(c, op, pc->fail_pop[pops]); NEXT_BLOCK(c); @@ -5570,6 +5569,13 @@ cleanup_fail_pop(struct compiler *c, pattern_context *pc) return 1; } +static int +compiler_error_duplicate_store(struct compiler *c, identifier n) +{ + const char *e = "multiple assignments to name %R in pattern"; + return compiler_error(c, e, n); +} + static int pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) @@ -5581,8 +5587,7 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) return 0; } if (duplicate) { - const char *e = "multiple assignments to name %R in pattern"; - return compiler_error(c, e, n); + return compiler_error_duplicate_store(c, n); } RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); // Rotate this object underneath any items we need to preserve: @@ -5676,15 +5681,14 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, else if (nstores != PyList_GET_SIZE(*control)) { goto diff; } - else if (-pc->adj < nstores) { + else if (nstores) { // There were captures. Check to see if we differ from the control list: if (is_last) { for (Py_ssize_t i = 0; i < pc->on_top; i++) { - ADDOP_I(c, ROT_N, nstores + pc->adj + pc->on_top); + ADDOP_I(c, ROT_N, nstores + pc->on_top); } } - for (Py_ssize_t icontrol = -pc->adj; icontrol < nstores; icontrol++) - { + for (Py_ssize_t icontrol = 0; icontrol < nstores; icontrol++) { PyObject *name = PyList_GET_ITEM(*control, icontrol); Py_ssize_t istores = PySequence_Index(pc->stores, name); if (istores < 0) { @@ -5719,17 +5723,15 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, } // The duplicate copy of the subject is under the new names. Rotate it // back to the top and pop it off. - for (Py_ssize_t i = 0; i < nstores + pc->adj; i++) { - ADDOP_I(c, ROT_N, nstores + pc->adj + on_top + !is_last); + for (Py_ssize_t i = 0; i < nstores; i++) { + ADDOP_I(c, ROT_N, nstores + on_top + !is_last); } if (!is_last) { ADDOP(c, POP_TOP); } ADDOP_JUMP(c, JUMP_FORWARD, end); NEXT_BLOCK(c); - if (!is_last) { - RETURN_IF_FALSE(cleanup_fail_pop(c, pc)); - } + RETURN_IF_FALSE(cleanup_fail_pop(c, pc)); return 1; diff: compiler_error(c, "alternative patterns bind different names"); @@ -5935,7 +5937,6 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // We're going to be messing with pc. Keep the original info handy: pattern_context old_pc = *pc; Py_INCREF(pc->stores); - Py_ssize_t old_nstores = PyList_GET_SIZE(pc->stores); // control is the list of names bound by the first alternative. It is used // for checking different name bindings in alternatives, and for correcting // the order in which extracted elements are placed on the stack. @@ -5944,42 +5945,50 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); SET_LOC(c, alt); int is_last = i == size - 1; - if (is_last) { - // For the last alternative, all control flow is basically "back to - // normal". Just use old_pc. - Py_DECREF(pc->stores); - *pc = old_pc; - Py_INCREF(pc->stores); - } - else { - // Set up a "fresh" pc containing only a copy of prior stores: - PyObject *pc_stores = PySequence_List(old_pc.stores); - if (pc_stores == NULL) { - Py_DECREF(old_pc.stores); - Py_XDECREF(control); - return 0; - } - Py_SETREF(pc->stores, pc_stores); - pc->allow_irrefutable = 0; - pc->fail_pop = NULL; - pc->fail_pop_size = 0; - pc->on_top = 0; - pc->adj = -old_nstores; + PyObject *pc_stores = PyList_New(0); + if (pc_stores == NULL) { + goto error; } + Py_SETREF(pc->stores, pc_stores); + pc->allow_irrefutable = is_last && old_pc.allow_irrefutable; + pc->fail_pop = NULL; + pc->fail_pop_size = 0; + pc->on_top = 0; if (!pattern_helper_or(c, alt, end, is_last, &control, old_pc.on_top, pc)) { - if (!is_last) { - PyObject_Free(old_pc.fail_pop); - } - Py_DECREF(old_pc.stores); - Py_XDECREF(control); - return 0; + goto error; } assert(control); } + Py_DECREF(pc->stores); + *pc = old_pc; + old_pc.fail_pop = NULL; + Py_INCREF(pc->stores); + if (!jump_to_fail_pop(c, pc, JUMP_FORWARD)) { + goto error; + } + for (Py_ssize_t i = 0; i < PyList_GET_SIZE(control); i++) { + PyObject *name = PyList_GET_ITEM(control, i); + int dupe = PySequence_Contains(old_pc.stores, name); + if (dupe < 0) { + goto error; + } + if (dupe) { + compiler_error_duplicate_store(c, name); + goto error; + } + if (PyList_Append(old_pc.stores, name)) { + goto error; + } + } Py_DECREF(old_pc.stores); Py_DECREF(control); compiler_use_next_block(c, end); return 1; +error: + PyObject_Free(old_pc.fail_pop); + Py_DECREF(old_pc.stores); + Py_XDECREF(control); + return 0; } @@ -6131,7 +6140,6 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - pc->adj = 0; // NOTE: Can't use returning macros here (they'll leak pc->stores)! if (!compiler_pattern(c, m->pattern, pc)) { Py_DECREF(pc->stores); From 26b49d4c73723e6f706409353694cad51ae30e6d Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 5 Apr 2021 16:32:56 -0700 Subject: [PATCH 31/47] A bit of cleanup --- Doc/library/dis.rst | 4 ++-- Python/compile.c | 25 +++++++++++-------------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 9bc5046669a02e..d2433c956d1880 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1250,8 +1250,8 @@ All of the following opcodes use their arguments. .. opcode:: ROT_N (count) - Lift top *count* stack items one position up, and move TOS down to position - *count*. + Lift the top *count* stack items one position up, and move TOS down to + position *count*. .. versionadded:: 3.10 diff --git a/Python/compile.c b/Python/compile.c index 6e990082883b5e..93902085b8c10d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5494,7 +5494,7 @@ compiler_slice(struct compiler *c, expr_ty s) // To keep things simple, all compiler_pattern_* and pattern_helper_* routines // follow the convention of consuming TOS (the subject for the given pattern) -// and calling pattern_context_jump_to_fail_pop on failure (no match). +// and calling jump_to_fail_pop on failure (no match). // When calling into these routines, it's important that pc->on_top be kept // updated to reflect the current number of items that we are using on the top @@ -5572,8 +5572,7 @@ cleanup_fail_pop(struct compiler *c, pattern_context *pc) static int compiler_error_duplicate_store(struct compiler *c, identifier n) { - const char *e = "multiple assignments to name %R in pattern"; - return compiler_error(c, e, n); + return compiler_error(c, "multiple assignments to name %R in pattern", n); } @@ -5662,7 +5661,7 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, static int pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, - PyObject **control, Py_ssize_t on_top, pattern_context *pc) + PyObject **control, pattern_context *pc) { // Only copy the subject if we're *not* on the last alternative: if (!is_last) { @@ -5683,11 +5682,6 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, } else if (nstores) { // There were captures. Check to see if we differ from the control list: - if (is_last) { - for (Py_ssize_t i = 0; i < pc->on_top; i++) { - ADDOP_I(c, ROT_N, nstores + pc->on_top); - } - } for (Py_ssize_t icontrol = 0; icontrol < nstores; icontrol++) { PyObject *name = PyList_GET_ITEM(*control, icontrol); Py_ssize_t istores = PySequence_Index(pc->stores, name); @@ -5724,7 +5718,7 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, // The duplicate copy of the subject is under the new names. Rotate it // back to the top and pop it off. for (Py_ssize_t i = 0; i < nstores; i++) { - ADDOP_I(c, ROT_N, nstores + on_top + !is_last); + ADDOP_I(c, ROT_N, nstores + !is_last); } if (!is_last) { ADDOP(c, POP_TOP); @@ -5950,11 +5944,12 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) goto error; } Py_SETREF(pc->stores, pc_stores); + // An irrefutable sub-pattern must be last, if it is allowed at all: pc->allow_irrefutable = is_last && old_pc.allow_irrefutable; pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - if (!pattern_helper_or(c, alt, end, is_last, &control, old_pc.on_top, pc)) { + if (!pattern_helper_or(c, alt, end, is_last, &control, pc)) { goto error; } assert(control); @@ -5966,7 +5961,8 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) if (!jump_to_fail_pop(c, pc, JUMP_FORWARD)) { goto error; } - for (Py_ssize_t i = 0; i < PyList_GET_SIZE(control); i++) { + Py_ssize_t nstores = PyList_GET_SIZE(control); + for (Py_ssize_t i = 0; i < nstores; i++) { PyObject *name = PyList_GET_ITEM(control, i); int dupe = PySequence_Contains(old_pc.stores, name); if (dupe < 0) { @@ -5983,6 +5979,9 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) Py_DECREF(old_pc.stores); Py_DECREF(control); compiler_use_next_block(c, end); + for (Py_ssize_t i = 0; i < nstores; i++) { + ADDOP_I(c, ROT_N, nstores + pc->on_top); + } return 1; error: PyObject_Free(old_pc.fail_pop); @@ -6082,7 +6081,6 @@ static int compiler_pattern(struct compiler *c, expr_ty p, pattern_context *pc) { SET_LOC(c, p); - int res; switch (p->kind) { case Attribute_kind: return compiler_pattern_value(c, p, pc); @@ -6113,7 +6111,6 @@ compiler_pattern(struct compiler *c, expr_ty p, pattern_context *pc) default: Py_UNREACHABLE(); } - return res; } From df70e5a92dbcd0d8cf4b278bd71e9613e1549fbc Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 5 Apr 2021 19:13:43 -0700 Subject: [PATCH 32/47] Fold rotations when possible --- Lib/importlib/_bootstrap_external.py | 2 +- Python/compile.c | 40 ++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 9fdb6fdfad7f47..1b2a2c4edf2ffe 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -315,7 +315,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.10a2 3433 (RERAISE restores f_lasti if oparg != 0) # Python 3.10a6 3434 (PEP 634: Structural Pattern Matching) # Python 3.10a7 3435 Use instruction offsets (as opposed to byte offsets). -# Python 3.10XX 3436 (add ROT_N opcode) +# Python 3.10b1 3436 (add ROT_N opcode) # # MAGIC must change whenever the bytecode emitted by the compiler may no diff --git a/Python/compile.c b/Python/compile.c index 93902085b8c10d..509a1bfb637845 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5715,12 +5715,13 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, } } } - // The duplicate copy of the subject is under the new names. Rotate it - // back to the top and pop it off. - for (Py_ssize_t i = 0; i < nstores; i++) { - ADDOP_I(c, ROT_N, nstores + !is_last); - } if (!is_last) { + // The duplicate copy of the subject is underneath the new names. Rotate + // it back to the top and pop it off. This could be made more efficient + // by performing a single "UNROT_N" instead of a bunch of ROT_Ns. + for (Py_ssize_t i = 0; i < nstores; i++) { + ADDOP_I(c, ROT_N, nstores + 1); + } ADDOP(c, POP_TOP); } ADDOP_JUMP(c, JUMP_FORWARD, end); @@ -6879,6 +6880,25 @@ fold_tuple_on_constants(struct instr *inst, } +// Eliminate N * ROT_N. +static void +fold_rotations(struct instr *inst, int n) +{ + for (int i = 0; i < n; i++) { + if ((n == 2 && inst[i].i_opcode != ROT_TWO) || + (n == 3 && inst[i].i_opcode != ROT_THREE) || + (n == 4 && inst[i].i_opcode != ROT_FOUR) || + (inst[i].i_opcode != ROT_N || inst[i].i_oparg != n)) + { + return; + } + } + for (int i = 0; i < n; i++) { + inst[i].i_opcode = NOP; + } +} + + static int eliminate_jump_to_jump(basicblock *bb, int opcode) { assert (bb->b_iused > 0); @@ -7138,6 +7158,16 @@ optimize_basic_block(basicblock *bb, PyObject *consts) inst->i_opcode = ROT_FOUR; break; } + case ROT_TWO: + case ROT_THREE: + case ROT_FOUR: + oparg = (2 * (inst->i_opcode == ROT_TWO) + + 3 * (inst->i_opcode == ROT_THREE) + + 4 * (inst->i_opcode == ROT_FOUR) + + oparg * (inst->i_opcode == ROT_N)); + if (oparg <= i) { + fold_rotations(inst - oparg + 1, oparg); + } break; } } From 26ba113ed7c87a5784743e425dc32bd24f215cf0 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Mon, 5 Apr 2021 22:04:04 -0700 Subject: [PATCH 33/47] More cleanup --- Python/compile.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 509a1bfb637845..56082c0d2771ad 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5502,8 +5502,6 @@ compiler_slice(struct compiler *c, expr_ty s) // stored *underneath* them on success. This lets us defer all names stores // until the *entire* pattern matches. -// TODO: variants of test_patma_283 with mappings, classes, stars, stores before/after - #define WILDCARD_CHECK(N) \ ((N)->kind == Name_kind && \ @@ -5957,15 +5955,18 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) } Py_DECREF(pc->stores); *pc = old_pc; - old_pc.fail_pop = NULL; Py_INCREF(pc->stores); + // Need to NULL this for the PyObject_Free call in the error block. + old_pc.fail_pop = NULL; if (!jump_to_fail_pop(c, pc, JUMP_FORWARD)) { goto error; } + // Update the list of previous stores with the names in the control list, + // checking for duplicates: Py_ssize_t nstores = PyList_GET_SIZE(control); for (Py_ssize_t i = 0; i < nstores; i++) { PyObject *name = PyList_GET_ITEM(control, i); - int dupe = PySequence_Contains(old_pc.stores, name); + int dupe = PySequence_Contains(pc->stores, name); if (dupe < 0) { goto error; } @@ -5973,7 +5974,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) compiler_error_duplicate_store(c, name); goto error; } - if (PyList_Append(old_pc.stores, name)) { + if (PyList_Append(pc->stores, name)) { goto error; } } From db9a3b1714aecf42aa51bc73ac191855e774a25c Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Tue, 6 Apr 2021 09:23:40 -0700 Subject: [PATCH 34/47] A bit more cleanup --- Python/compile.c | 115 +++++++++++++++++++---------------------------- 1 file changed, 45 insertions(+), 70 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 56082c0d2771ad..31ff6646d23919 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5587,8 +5587,10 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) return compiler_error_duplicate_store(c, n); } RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); - // Rotate this object underneath any items we need to preserve: - ADDOP_I(c, ROT_N, pc->on_top + 1); + if (pc->on_top) { + // Rotate this object underneath any items we need to preserve: + ADDOP_I(c, ROT_N, pc->on_top + 1); + } return 1; } @@ -5658,16 +5660,13 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, static int -pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, +pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, PyObject **control, pattern_context *pc) { - // Only copy the subject if we're *not* on the last alternative: - if (!is_last) { - ADDOP(c, DUP_TOP); - } + ADDOP(c, DUP_TOP); RETURN_IF_FALSE(compiler_pattern(c, p, pc)); - Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); // Success! + Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); if (*control == NULL) { // This is the first alternative, so save its stores as a "control" for // the others (they can't bind a different set of names, and might need @@ -5687,41 +5686,34 @@ pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, int is_last, PyErr_Clear(); goto diff; } - // Reorder the names on the stack to match the order of the names in - // control. There's probably a better way of doing this; the current - // solution is potentially very inefficient when each alternative - // subpattern binds lots of names in different orders. It's fine for - // reasonable cases, though. - assert(icontrol <= istores); - // Perfom the same rotation on pc->stores: - PyObject *rotate = PyList_GetSlice(pc->stores, istores, nstores); - if (rotate == NULL || - PyList_SetSlice(pc->stores, istores, nstores, NULL) || - PyList_SetSlice(pc->stores, icontrol, icontrol, rotate)) - { - Py_XDECREF(rotate); - return 0; - } - Py_DECREF(rotate); - // That just did: - // rotate = pc_stores[istores:] - // del pc_stores[istores:] - // pc_stores[icontrol:icontrol] = rotate - // Do the exact same thing to the stack, using several rotations: - while (istores++ < nstores) { - ADDOP_I(c, ROT_N, nstores - icontrol); + if (icontrol != istores) { + // Reorder the names on the stack to match the order of the + // names in control. There's probably a better way of doing + // this; the current solution is potentially very inefficient + // when each alternative subpattern binds lots of names in + // different orders. It's fine for reasonable cases, though. + assert(icontrol < istores); + // Perfom the same rotation on pc->stores: + PyObject *rotate = PyList_GetSlice(pc->stores, istores, nstores); + if (rotate == NULL || + PyList_SetSlice(pc->stores, istores, nstores, NULL) || + PyList_SetSlice(pc->stores, icontrol, icontrol, rotate)) + { + Py_XDECREF(rotate); + return 0; + } + Py_DECREF(rotate); + // That just did: + // rotate = pc_stores[istores:] + // del pc_stores[istores:] + // pc_stores[icontrol:icontrol] = rotate + // Do the same thing to the stack, using several rotations: + while (istores++ < nstores) { + ADDOP_I(c, ROT_N, nstores - icontrol); + } } } } - if (!is_last) { - // The duplicate copy of the subject is underneath the new names. Rotate - // it back to the top and pop it off. This could be made more efficient - // by performing a single "UNROT_N" instead of a bunch of ROT_Ns. - for (Py_ssize_t i = 0; i < nstores; i++) { - ADDOP_I(c, ROT_N, nstores + 1); - } - ADDOP(c, POP_TOP); - } ADDOP_JUMP(c, JUMP_FORWARD, end); NEXT_BLOCK(c); RETURN_IF_FALSE(cleanup_fail_pop(c, pc)); @@ -5948,7 +5940,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - if (!pattern_helper_or(c, alt, end, is_last, &control, pc)) { + if (!pattern_helper_or(c, alt, end, &control, pc)) { goto error; } assert(control); @@ -5958,7 +5950,8 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) Py_INCREF(pc->stores); // Need to NULL this for the PyObject_Free call in the error block. old_pc.fail_pop = NULL; - if (!jump_to_fail_pop(c, pc, JUMP_FORWARD)) { + // No match. Pop the remaining copy of the subject and fail: + if (!compiler_addop(c, POP_TOP) || !jump_to_fail_pop(c, pc, JUMP_FORWARD)) { goto error; } // Update the list of previous stores with the names in the control list, @@ -5981,9 +5974,14 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) Py_DECREF(old_pc.stores); Py_DECREF(control); compiler_use_next_block(c, end); + // There is a copy of the subject underneath all of the new name stores. + // There may also be important items under it that need to be rotated back + // up to the top: for (Py_ssize_t i = 0; i < nstores; i++) { - ADDOP_I(c, ROT_N, nstores + pc->on_top); + ADDOP_I(c, ROT_N, nstores + pc->on_top + 1); } + // Pop the copy of the subject: + ADDOP(c, POP_TOP); return 1; error: PyObject_Free(old_pc.fail_pop); @@ -6886,11 +6884,7 @@ static void fold_rotations(struct instr *inst, int n) { for (int i = 0; i < n; i++) { - if ((n == 2 && inst[i].i_opcode != ROT_TWO) || - (n == 3 && inst[i].i_opcode != ROT_THREE) || - (n == 4 && inst[i].i_opcode != ROT_FOUR) || - (inst[i].i_opcode != ROT_N || inst[i].i_oparg != n)) - { + if (inst[i].i_opcode != ROT_N || inst[i].i_oparg != n) { return; } } @@ -7144,29 +7138,10 @@ optimize_basic_block(basicblock *bb, PyObject *consts) } break; case ROT_N: - switch (oparg) { - case 0: - case 1: - inst->i_opcode = NOP; - break; - case 2: - inst->i_opcode = ROT_TWO; - break; - case 3: - inst->i_opcode = ROT_THREE; - break; - case 4: - inst->i_opcode = ROT_FOUR; - break; + if (oparg < 2) { + inst->i_opcode = NOP; } - case ROT_TWO: - case ROT_THREE: - case ROT_FOUR: - oparg = (2 * (inst->i_opcode == ROT_TWO) + - 3 * (inst->i_opcode == ROT_THREE) + - 4 * (inst->i_opcode == ROT_FOUR) + - oparg * (inst->i_opcode == ROT_N)); - if (oparg <= i) { + else if (i >= oparg - 1) { fold_rotations(inst - oparg + 1, oparg); } break; From 2c53ec51ffed0664afe25ecd36e40f3fb2f3b062 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Tue, 6 Apr 2021 12:29:10 -0700 Subject: [PATCH 35/47] Ditch pattern_helper_or --- Python/compile.c | 135 +++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 68 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 0f793f9e560324..dfba8068187836 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5569,6 +5569,7 @@ cleanup_fail_pop(struct compiler *c, pattern_context *pc) return 1; } + static int compiler_error_duplicate_store(struct compiler *c, identifier n) { @@ -5661,71 +5662,6 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_expr_seq *values, } -static int -pattern_helper_or(struct compiler *c, expr_ty p, basicblock *end, - PyObject **control, pattern_context *pc) -{ - ADDOP(c, DUP_TOP); - RETURN_IF_FALSE(compiler_pattern(c, p, pc)); - // Success! - Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); - if (*control == NULL) { - // This is the first alternative, so save its stores as a "control" for - // the others (they can't bind a different set of names, and might need - // to be reordered): - *control = pc->stores; - Py_INCREF(*control); - } - else if (nstores != PyList_GET_SIZE(*control)) { - goto diff; - } - else if (nstores) { - // There were captures. Check to see if we differ from the control list: - for (Py_ssize_t icontrol = 0; icontrol < nstores; icontrol++) { - PyObject *name = PyList_GET_ITEM(*control, icontrol); - Py_ssize_t istores = PySequence_Index(pc->stores, name); - if (istores < 0) { - PyErr_Clear(); - goto diff; - } - if (icontrol != istores) { - // Reorder the names on the stack to match the order of the - // names in control. There's probably a better way of doing - // this; the current solution is potentially very inefficient - // when each alternative subpattern binds lots of names in - // different orders. It's fine for reasonable cases, though. - assert(icontrol < istores); - // Perfom the same rotation on pc->stores: - PyObject *rotate = PyList_GetSlice(pc->stores, istores, nstores); - if (rotate == NULL || - PyList_SetSlice(pc->stores, istores, nstores, NULL) || - PyList_SetSlice(pc->stores, icontrol, icontrol, rotate)) - { - Py_XDECREF(rotate); - return 0; - } - Py_DECREF(rotate); - // That just did: - // rotate = pc_stores[istores:] - // del pc_stores[istores:] - // pc_stores[icontrol:icontrol] = rotate - // Do the same thing to the stack, using several rotations: - while (istores++ < nstores) { - ADDOP_I(c, ROT_N, nstores - icontrol); - } - } - } - } - ADDOP_JUMP(c, JUMP_FORWARD, end); - NEXT_BLOCK(c); - RETURN_IF_FALSE(cleanup_fail_pop(c, pc)); - return 1; -diff: - compiler_error(c, "alternative patterns bind different names"); - return 0; -} - - // Like compiler_pattern, but turn off checks for irrefutability. static int compiler_pattern_subpattern(struct compiler *c, expr_ty p, pattern_context *pc) @@ -5924,6 +5860,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // We're going to be messing with pc. Keep the original info handy: pattern_context old_pc = *pc; Py_INCREF(pc->stores); + // NOTE: We can't use returning macros anymore! goto error on error. // control is the list of names bound by the first alternative. It is used // for checking different name bindings in alternatives, and for correcting // the order in which extracted elements are placed on the stack. @@ -5931,21 +5868,80 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) for (Py_ssize_t i = 0; i < size; i++) { expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); SET_LOC(c, alt); - int is_last = i == size - 1; PyObject *pc_stores = PyList_New(0); if (pc_stores == NULL) { goto error; } Py_SETREF(pc->stores, pc_stores); // An irrefutable sub-pattern must be last, if it is allowed at all: - pc->allow_irrefutable = is_last && old_pc.allow_irrefutable; + pc->allow_irrefutable = (i == size - 1) && old_pc.allow_irrefutable; pc->fail_pop = NULL; pc->fail_pop_size = 0; pc->on_top = 0; - if (!pattern_helper_or(c, alt, end, &control, pc)) { + if (!compiler_addop(c, DUP_TOP) || !compiler_pattern(c, alt, pc)) { goto error; } + // Success! + Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); + if (!i) { + // This is the first alternative, so save its stores as a "control" + // for the others (they can't bind a different set of names, and + // might need to be reordered): + assert(control == NULL); + control = pc->stores; + Py_INCREF(control); + } + else if (nstores != PyList_GET_SIZE(control)) { + goto diff; + } + else if (nstores) { + // There were captures. Check to see if we differ from control: + for (Py_ssize_t icontrol = 0; icontrol < nstores; icontrol++) { + PyObject *name = PyList_GET_ITEM(control, icontrol); + Py_ssize_t istores = PySequence_Index(pc->stores, name); + if (istores < 0) { + PyErr_Clear(); + goto diff; + } + if (icontrol != istores) { + // Reorder the names on the stack to match the order of the + // names in control. There's probably a better way of doing + // this; the current solution is potentially very + // inefficient when each alternative subpattern binds lots + // of names in different orders. It's fine for reasonable + // cases, though. + assert(icontrol < istores); + // Perfom the same rotation on pc->stores: + PyObject *rotate = PyList_GetSlice(pc->stores, istores, + nstores); + if (rotate == NULL || + PyList_SetSlice(pc->stores, istores, nstores, NULL) || + PyList_SetSlice(pc->stores, icontrol, icontrol, rotate)) + { + Py_XDECREF(rotate); + goto error; + } + Py_DECREF(rotate); + // That just did: + // rotate = pc_stores[istores:] + // del pc_stores[istores:] + // pc_stores[icontrol:icontrol] = rotate + // Do the same thing to the stack, using several rotations: + while (istores++ < nstores) { + if (!compiler_addop_i(c, ROT_N, nstores - icontrol)) { + goto error; + } + } + } + } + } assert(control); + if (!compiler_addop_j(c, JUMP_FORWARD, end) || + !compiler_next_block(c) || + !cleanup_fail_pop(c, pc)) + { + goto error; + } } Py_DECREF(pc->stores); *pc = old_pc; @@ -5975,6 +5971,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) } Py_DECREF(old_pc.stores); Py_DECREF(control); + // NOTE: Returning macros are safe again. compiler_use_next_block(c, end); // There is a copy of the subject underneath all of the new name stores. // There may also be important items under it that need to be rotated back @@ -5985,6 +5982,8 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // Pop the copy of the subject: ADDOP(c, POP_TOP); return 1; +diff: + compiler_error(c, "alternative patterns bind different names"); error: PyObject_Free(old_pc.fail_pop); Py_DECREF(old_pc.stores); From 92558162f394b11fb7294e71464d8bbff3082c0d Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Tue, 6 Apr 2021 12:42:40 -0700 Subject: [PATCH 36/47] Move comment --- Python/compile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/compile.c b/Python/compile.c index dfba8068187836..caf35a88e9fab5 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5860,11 +5860,11 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // We're going to be messing with pc. Keep the original info handy: pattern_context old_pc = *pc; Py_INCREF(pc->stores); - // NOTE: We can't use returning macros anymore! goto error on error. // control is the list of names bound by the first alternative. It is used // for checking different name bindings in alternatives, and for correcting // the order in which extracted elements are placed on the stack. PyObject *control = NULL; + // NOTE: We can't use returning macros anymore! goto error on error. for (Py_ssize_t i = 0; i < size; i++) { expr_ty alt = asdl_seq_GET(p->v.MatchOr.patterns, i); SET_LOC(c, alt); From 169c6eb5d25b6bbc50d7ef47f51d3481f1681296 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Tue, 6 Apr 2021 16:50:41 -0700 Subject: [PATCH 37/47] Fix possible bad free --- Python/compile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/compile.c b/Python/compile.c index caf35a88e9fab5..8e30477bdecc1d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -6191,6 +6191,7 @@ static int compiler_match(struct compiler *c, stmt_ty s) { pattern_context pc; + pc.fail_pop = NULL; int result = compiler_match_inner(c, s, &pc); PyObject_Free(pc.fail_pop); return result; From 13bb083e334257bbe9d45b7bf7869334826c9c6b Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Fri, 23 Apr 2021 14:05:18 -0700 Subject: [PATCH 38/47] ROT_* -> ROTATE --- Doc/library/dis.rst | 21 +----------- Include/opcode.h | 5 +-- Lib/importlib/_bootstrap_external.py | 4 +-- Lib/opcode.py | 6 ++-- Lib/test/test_peepholer.py | 4 +-- Python/ceval.c | 35 +------------------ Python/compile.c | 51 ++++++++++++++-------------- Python/importlib.h | 34 +++++++++---------- Python/importlib_external.h | 18 +++++----- Python/importlib_zipimport.h | 6 ++-- Python/opcode_targets.h | 8 ++--- 11 files changed, 67 insertions(+), 125 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index ae3e5c6c60b5ab..3c8cff2ce7771c 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -333,25 +333,6 @@ The Python compiler currently generates the following bytecode instructions. Removes the top-of-stack (TOS) item. -.. opcode:: ROT_TWO - - Swaps the two top-most stack items. - - -.. opcode:: ROT_THREE - - Lifts second and third stack item one position up, moves top down to position - three. - - -.. opcode:: ROT_FOUR - - Lifts second, third and fourth stack items one position up, moves top down - to position four. - - .. versionadded:: 3.8 - - .. opcode:: DUP_TOP Duplicates the reference on top of the stack. @@ -1256,7 +1237,7 @@ All of the following opcodes use their arguments. .. versionadded:: 3.10 -.. opcode:: ROT_N (count) +.. opcode:: ROTATE (count) Lift the top *count* stack items one position up, and move TOS down to position *count*. diff --git a/Include/opcode.h b/Include/opcode.h index 52039754bd88ea..947c08f8aaab62 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -8,11 +8,8 @@ extern "C" { /* Instruction opcodes for compiled code */ #define POP_TOP 1 -#define ROT_TWO 2 -#define ROT_THREE 3 #define DUP_TOP 4 #define DUP_TOP_TWO 5 -#define ROT_FOUR 6 #define NOP 9 #define UNARY_POSITIVE 10 #define UNARY_NEGATIVE 11 @@ -81,7 +78,7 @@ extern "C" { #define DELETE_ATTR 96 #define STORE_GLOBAL 97 #define DELETE_GLOBAL 98 -#define ROT_N 99 +#define ROTATE 99 #define LOAD_CONST 100 #define LOAD_NAME 101 #define BUILD_TUPLE 102 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index db5fe0f6178a3f..a41a2de547fcd6 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -350,7 +350,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.10a7 3435 Use instruction offsets (as opposed to byte offsets). # Python 3.10b1 3436 (Add GEN_START bytecode #43683) # Python 3.10b1 3437 (Undo making 'annotations' future by default - We like to dance among core devs!) -# Python 3.10b1 3438 (add ROT_N opcode) +# Python 3.10b1 3438 (replace ROT_* with ROTATE) # # MAGIC must change whenever the bytecode emitted by the compiler may no @@ -360,7 +360,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 = (3437).to_bytes(2, 'little') + b'\r\n' +MAGIC_NUMBER = (3438).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 37e88e92df70ec..fab9a3b195908b 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -55,11 +55,9 @@ def jabs_op(name, op): # Blank lines correspond to available opcodes def_op('POP_TOP', 1) -def_op('ROT_TWO', 2) -def_op('ROT_THREE', 3) + def_op('DUP_TOP', 4) def_op('DUP_TOP_TWO', 5) -def_op('ROT_FOUR', 6) def_op('NOP', 9) def_op('UNARY_POSITIVE', 10) @@ -139,7 +137,7 @@ def jabs_op(name, op): name_op('DELETE_ATTR', 96) # "" name_op('STORE_GLOBAL', 97) # "" name_op('DELETE_GLOBAL', 98) # "" -def_op('ROT_N', 99) +def_op('ROTATE', 99) def_op('LOAD_CONST', 100) # Index in const list hasconst.append(100) name_op('LOAD_NAME', 101) # Index in name list diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 4034154e4dcfb5..61feff360e5c50 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -116,8 +116,8 @@ def f(): def test_pack_unpack(self): for line, elem in ( ('a, = a,', 'LOAD_CONST',), - ('a, b = a, b', 'ROT_TWO',), - ('a, b, c = a, b, c', 'ROT_THREE',), + ('a, b = a, b', 'ROTATE',), + ('a, b, c = a, b, c', 'ROTATE',), ): code = compile(line,'','single') self.assertInBytecode(code, elem) diff --git a/Python/ceval.c b/Python/ceval.c index 265e473173da41..acb40d70210633 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1395,12 +1395,9 @@ eval_frame_handle_pending(PyThreadState *tstate) #define TOP() (stack_pointer[-1]) #define SECOND() (stack_pointer[-2]) #define THIRD() (stack_pointer[-3]) -#define FOURTH() (stack_pointer[-4]) #define PEEK(n) (stack_pointer[-(n)]) #define SET_TOP(v) (stack_pointer[-1] = (v)) #define SET_SECOND(v) (stack_pointer[-2] = (v)) -#define SET_THIRD(v) (stack_pointer[-3] = (v)) -#define SET_FOURTH(v) (stack_pointer[-4] = (v)) #define BASIC_STACKADJ(n) (stack_pointer += n) #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define BASIC_POP() (*--stack_pointer) @@ -1879,36 +1876,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) DISPATCH(); } - case TARGET(ROT_TWO): { - PyObject *top = TOP(); - PyObject *second = SECOND(); - SET_TOP(second); - SET_SECOND(top); - DISPATCH(); - } - - case TARGET(ROT_THREE): { - PyObject *top = TOP(); - PyObject *second = SECOND(); - PyObject *third = THIRD(); - SET_TOP(second); - SET_SECOND(third); - SET_THIRD(top); - DISPATCH(); - } - - case TARGET(ROT_FOUR): { - PyObject *top = TOP(); - PyObject *second = SECOND(); - PyObject *third = THIRD(); - PyObject *fourth = FOURTH(); - SET_TOP(second); - SET_SECOND(third); - SET_THIRD(fourth); - SET_FOURTH(top); - DISPATCH(); - } - case TARGET(DUP_TOP): { PyObject *top = TOP(); Py_INCREF(top); @@ -4455,7 +4422,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) DISPATCH(); } - case TARGET(ROT_N): { + case TARGET(ROTATE): { PyObject *top = TOP(); memmove(&PEEK(oparg - 1), &PEEK(oparg), sizeof(PyObject*) * (oparg - 1)); diff --git a/Python/compile.c b/Python/compile.c index fa645f5d338dff..d8be391584d717 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -959,10 +959,6 @@ stack_effect(int opcode, int oparg, int jump) /* Stack manipulation */ case POP_TOP: return -1; - case ROT_TWO: - case ROT_THREE: - case ROT_FOUR: - return 0; case DUP_TOP: return 1; case DUP_TOP_TWO: @@ -1208,7 +1204,7 @@ stack_effect(int opcode, int oparg, int jump) return 1; case MATCH_KEYS: return 2; - case ROT_N: + case ROTATE: return 0; default: return PY_INVALID_STACK_EFFECT; @@ -1776,7 +1772,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case FOR_LOOP: /* Pop the iterator */ if (preserve_tos) { - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); } ADDOP(c, POP_TOP); return 1; @@ -1806,13 +1802,13 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case FINALLY_END: if (preserve_tos) { - ADDOP(c, ROT_FOUR); + ADDOP_I(c, ROTATE, 4); } ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); if (preserve_tos) { - ADDOP(c, ROT_FOUR); + ADDOP_I(c, ROTATE, 4); } ADDOP(c, POP_EXCEPT); return 1; @@ -1821,7 +1817,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case ASYNC_WITH: ADDOP(c, POP_BLOCK); if (preserve_tos) { - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); } if(!compiler_call_exit_with_nones(c)) { return 0; @@ -1839,7 +1835,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, ADDOP(c, POP_BLOCK); } if (preserve_tos) { - ADDOP(c, ROT_FOUR); + ADDOP_I(c, ROTATE, 4); } ADDOP(c, POP_EXCEPT); if (info->fb_datum) { @@ -1851,7 +1847,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case POP_VALUE: if (preserve_tos) { - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); } ADDOP(c, POP_TOP); return 1; @@ -2690,7 +2686,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP(c, DUP_TOP); - ADDOP(c, ROT_THREE); + ADDOP_I(c, ROTATE, 3); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, cleanup); NEXT_BLOCK(c); @@ -3294,7 +3290,7 @@ compiler_import_as(struct compiler *c, identifier name, identifier asname) if (dot == -1) { break; } - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); ADDOP(c, POP_TOP); } if (!compiler_nameop(c, asname, Store)) { @@ -4072,7 +4068,7 @@ compiler_compare(struct compiler *c, expr_ty e) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP(c, DUP_TOP); - ADDOP(c, ROT_THREE); + ADDOP_I(c, ROTATE, 3); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, cleanup); NEXT_BLOCK(c); @@ -4084,7 +4080,7 @@ compiler_compare(struct compiler *c, expr_ty e) return 0; ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); compiler_use_next_block(c, cleanup); - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); ADDOP(c, POP_TOP); compiler_use_next_block(c, end); } @@ -5352,11 +5348,11 @@ compiler_augassign(struct compiler *c, stmt_ty s) switch (e->kind) { case Attribute_kind: c->u->u_lineno = e->end_lineno; - ADDOP(c, ROT_TWO); + ADDOP_I(c, ROTATE, 2); ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); break; case Subscript_kind: - ADDOP(c, ROT_THREE); + ADDOP_I(c, ROTATE, 3); ADDOP(c, STORE_SUBSCR); break; case Name_kind: @@ -5708,7 +5704,7 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); if (pc->on_top) { // Rotate this object underneath any items we need to preserve: - ADDOP_I(c, ROT_N, pc->on_top + 1); + ADDOP_I(c, ROTATE, pc->on_top + 1); } return 1; } @@ -6044,7 +6040,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // pc_stores[icontrol:icontrol] = rotate // Do the same thing to the stack, using several rotations: while (istores++ < nstores) { - if (!compiler_addop_i(c, ROT_N, nstores - icontrol)) { + if (!compiler_addop_i(c, ROTATE, nstores - icontrol)) { goto error; } } @@ -6093,7 +6089,7 @@ compiler_pattern_or(struct compiler *c, expr_ty p, pattern_context *pc) // There may also be important items under it that need to be rotated back // up to the top: for (Py_ssize_t i = 0; i < nstores; i++) { - ADDOP_I(c, ROT_N, nstores + pc->on_top + 1); + ADDOP_I(c, ROTATE, nstores + pc->on_top + 1); } // Pop the copy of the subject: ADDOP(c, POP_TOP); @@ -7060,12 +7056,12 @@ fold_tuple_on_constants(struct compiler *c, } -// Eliminate N * ROT_N. +// Eliminate N * ROTATE. static void fold_rotations(struct instr *inst, int n) { for (int i = 0; i < n; i++) { - if (inst[i].i_opcode != ROT_N || inst[i].i_oparg != n) { + if (inst[i].i_opcode != ROTATE || inst[i].i_oparg != n) { return; } } @@ -7178,12 +7174,15 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) bb->b_instr[i+1].i_opcode = NOP; break; case 2: - inst->i_opcode = ROT_TWO; + inst->i_opcode = ROTATE; + inst->i_oparg = 2; bb->b_instr[i+1].i_opcode = NOP; break; case 3: - inst->i_opcode = ROT_THREE; - bb->b_instr[i+1].i_opcode = ROT_TWO; + inst->i_opcode = ROTATE; + inst->i_oparg = 3; + bb->b_instr[i+1].i_opcode = ROTATE; + bb->b_instr[i+1].i_oparg = 2; } break; } @@ -7318,7 +7317,7 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) } } break; - case ROT_N: + case ROTATE: if (oparg < 2) { inst->i_opcode = NOP; } diff --git a/Python/importlib.h b/Python/importlib.h index ea00ff36d73916..92faa5e8795310 100644 --- a/Python/importlib.h +++ b/Python/importlib.h @@ -56,7 +56,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8, 0,0,0,67,0,0,0,115,38,0,0,0,122,4,124,0, 106,0,87,0,83,0,4,0,116,1,121,18,1,0,1,0, - 1,0,116,2,124,0,131,1,106,0,6,0,89,0,83,0, + 1,0,116,2,124,0,131,1,106,0,99,4,89,0,83,0, 119,0,169,1,78,41,3,218,12,95,95,113,117,97,108,110, 97,109,101,95,95,218,14,65,116,116,114,105,98,117,116,101, 69,114,114,111,114,218,4,116,121,112,101,41,1,218,3,111, @@ -154,11 +154,11 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 60,0,122,86,9,0,124,0,106,3,143,63,1,0,124,0, 106,4,100,2,107,2,115,24,124,0,106,5,124,1,107,2, 114,46,124,1,124,0,95,5,124,0,4,0,106,4,100,3, - 55,0,2,0,95,4,87,0,100,4,4,0,4,0,131,3, + 55,0,99,2,95,4,87,0,100,4,4,0,4,0,131,3, 1,0,87,0,116,2,124,1,61,0,100,1,83,0,124,0, 160,6,161,0,114,56,116,7,100,5,124,0,22,0,131,1, 130,1,124,0,106,8,160,9,100,6,161,1,114,69,124,0, - 4,0,106,10,100,3,55,0,2,0,95,10,87,0,100,4, + 4,0,106,10,100,3,55,0,99,2,95,10,87,0,100,4, 4,0,4,0,131,3,1,0,110,8,49,0,115,79,119,1, 1,0,1,0,1,0,89,0,1,0,124,0,106,8,160,9, 161,0,1,0,124,0,106,8,160,11,161,0,1,0,113,10, @@ -192,10 +192,10 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 115,144,0,0,0,116,0,160,1,161,0,125,1,124,0,106, 2,143,55,1,0,124,0,106,3,124,1,107,3,114,17,116, 4,100,1,131,1,130,1,124,0,106,5,100,2,107,4,115, - 24,74,0,130,1,124,0,4,0,106,5,100,3,56,0,2, - 0,95,5,124,0,106,5,100,2,107,2,114,54,100,0,124, + 24,74,0,130,1,124,0,4,0,106,5,100,3,56,0,99, + 2,95,5,124,0,106,5,100,2,107,2,114,54,100,0,124, 0,95,3,124,0,106,6,114,54,124,0,4,0,106,6,100, - 3,56,0,2,0,95,6,124,0,106,7,160,8,161,0,1, + 3,56,0,99,2,95,6,124,0,106,7,160,8,161,0,1, 0,87,0,100,0,4,0,4,0,131,3,1,0,100,0,83, 0,49,0,115,65,119,1,1,0,1,0,1,0,89,0,1, 0,100,0,83,0,41,4,78,250,31,99,97,110,110,111,116, @@ -248,7 +248,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 100,117,108,101,76,111,99,107,46,95,95,105,110,105,116,95, 95,99,1,0,0,0,0,0,0,0,0,0,0,0,1,0, 0,0,3,0,0,0,67,0,0,0,115,18,0,0,0,124, - 0,4,0,106,0,100,1,55,0,2,0,95,0,100,2,83, + 0,4,0,106,0,100,1,55,0,99,2,95,0,100,2,83, 0,41,3,78,114,42,0,0,0,84,41,1,114,30,0,0, 0,114,52,0,0,0,114,5,0,0,0,114,5,0,0,0, 114,6,0,0,0,114,43,0,0,0,150,0,0,0,115,6, @@ -257,7 +257,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 105,114,101,99,1,0,0,0,0,0,0,0,0,0,0,0, 1,0,0,0,3,0,0,0,67,0,0,0,115,36,0,0, 0,124,0,106,0,100,1,107,2,114,9,116,1,100,2,131, - 1,130,1,124,0,4,0,106,0,100,3,56,0,2,0,95, + 1,130,1,124,0,4,0,106,0,100,3,56,0,99,2,95, 0,100,0,83,0,41,4,78,114,25,0,0,0,114,46,0, 0,0,114,42,0,0,0,41,2,114,30,0,0,0,114,47, 0,0,0,114,52,0,0,0,114,5,0,0,0,114,5,0, @@ -529,8 +529,8 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 1,0,1,0,1,0,100,5,125,3,89,0,122,5,124,0, 106,7,125,4,87,0,110,25,4,0,116,6,121,89,1,0, 1,0,1,0,124,1,100,2,117,0,114,75,100,6,160,8, - 124,3,161,1,6,0,89,0,83,0,100,7,160,8,124,3, - 124,1,161,2,6,0,89,0,83,0,100,8,160,8,124,3, + 124,3,161,1,99,4,89,0,83,0,100,7,160,8,124,3, + 124,1,161,2,99,4,89,0,83,0,100,8,160,8,124,3, 124,4,161,2,83,0,119,0,119,0,119,0,41,9,122,44, 84,104,101,32,105,109,112,108,101,109,101,110,116,97,116,105, 111,110,32,111,102,32,77,111,100,117,108,101,84,121,112,101, @@ -705,7 +705,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 107,2,111,38,124,2,124,1,106,0,107,2,111,38,124,0, 106,4,124,1,106,4,107,2,111,38,124,0,106,5,124,1, 106,5,107,2,87,0,83,0,4,0,116,6,121,50,1,0, - 1,0,1,0,116,7,6,0,89,0,83,0,119,0,114,0, + 1,0,1,0,116,7,99,4,89,0,83,0,119,0,114,0, 0,0,0,41,8,114,129,0,0,0,114,20,0,0,0,114, 122,0,0,0,114,126,0,0,0,218,6,99,97,99,104,101, 100,218,12,104,97,115,95,108,111,99,97,116,105,111,110,114, @@ -1047,7 +1047,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 254,2,245,255,128,114,173,0,0,0,99,1,0,0,0,0, 0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,67, 0,0,0,115,54,0,0,0,116,0,124,0,106,1,131,1, - 143,12,1,0,116,2,124,0,131,1,87,0,2,0,100,1, + 143,12,1,0,116,2,124,0,131,1,87,0,99,2,100,1, 4,0,4,0,131,3,1,0,83,0,49,0,115,20,119,1, 1,0,1,0,1,0,89,0,1,0,100,1,83,0,41,2, 122,191,82,101,116,117,114,110,32,97,32,110,101,119,32,109, @@ -1466,10 +1466,10 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,89,0,1,0,124,7,100,1,117,1,114,135,124,4,115, 131,124,0,116,0,106,6,118,0,114,131,116,0,106,6,124, 0,25,0,125,8,122,5,124,8,106,11,125,9,87,0,110, - 12,4,0,116,9,121,138,1,0,1,0,1,0,124,7,6, - 0,89,0,2,0,1,0,83,0,124,9,100,1,117,0,114, - 127,124,7,2,0,1,0,83,0,124,9,2,0,1,0,83, - 0,124,7,2,0,1,0,83,0,113,26,100,1,83,0,119, + 12,4,0,116,9,121,138,1,0,1,0,1,0,124,7,99, + 4,89,0,99,2,1,0,83,0,124,9,100,1,117,0,114, + 127,124,7,99,2,1,0,83,0,124,9,99,2,1,0,83, + 0,124,7,99,2,1,0,83,0,113,26,100,1,83,0,119, 0,119,0,41,4,122,21,70,105,110,100,32,97,32,109,111, 100,117,108,101,39,115,32,115,112,101,99,46,78,122,53,115, 121,115,46,109,101,116,97,95,112,97,116,104,32,105,115,32, @@ -1569,7 +1569,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,0,0,8,0,0,0,67,0,0,0,115,128,0,0,0, 116,0,124,0,131,1,143,31,1,0,116,1,106,2,160,3, 124,0,116,4,161,2,125,2,124,2,116,4,117,0,114,28, - 116,5,124,0,124,1,131,2,87,0,2,0,100,1,4,0, + 116,5,124,0,124,1,131,2,87,0,99,2,100,1,4,0, 4,0,131,3,1,0,83,0,87,0,100,1,4,0,4,0, 131,3,1,0,110,8,49,0,115,38,119,1,1,0,1,0, 1,0,89,0,1,0,124,2,100,1,117,0,114,58,100,2, diff --git a/Python/importlib_external.h b/Python/importlib_external.h index e4e6f0a238449e..083b746bf9217c 100644 --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -359,7 +359,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 99,185,0,0,0,115,38,0,0,0,16,5,6,1,22,1, 4,255,2,2,14,3,24,1,16,128,18,1,12,1,2,1, 12,1,2,3,12,254,2,1,2,1,2,254,2,253,255,128, - 114,95,0,0,0,105,109,13,0,0,114,44,0,0,0,114, + 114,95,0,0,0,105,110,13,0,0,114,44,0,0,0,114, 32,0,0,0,115,2,0,0,0,13,10,90,11,95,95,112, 121,99,97,99,104,101,95,95,122,4,111,112,116,45,122,3, 46,112,121,122,4,46,112,121,119,122,4,46,112,121,99,41, @@ -1071,7 +1071,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 8,0,0,0,67,0,0,0,115,50,0,0,0,122,8,116, 0,160,1,116,0,106,2,124,0,161,2,87,0,83,0,4, 0,116,3,121,24,1,0,1,0,1,0,116,0,160,1,116, - 0,106,4,124,0,161,2,6,0,89,0,83,0,119,0,114, + 0,106,4,124,0,161,2,99,4,89,0,83,0,119,0,114, 69,0,0,0,41,5,218,6,119,105,110,114,101,103,90,7, 79,112,101,110,75,101,121,90,17,72,75,69,89,95,67,85, 82,82,69,78,84,95,85,83,69,82,114,76,0,0,0,90, @@ -1119,7 +1119,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 83,0,116,3,131,0,68,0,93,26,92,2,125,5,125,6, 124,4,160,4,116,5,124,6,131,1,161,1,114,56,116,6, 106,7,124,1,124,5,124,1,124,4,131,2,124,4,100,1, - 141,3,125,7,124,7,2,0,1,0,83,0,113,30,100,0, + 141,3,125,7,124,7,99,2,1,0,83,0,113,30,100,0, 83,0,119,0,41,2,78,114,204,0,0,0,41,8,114,223, 0,0,0,114,75,0,0,0,114,76,0,0,0,114,208,0, 0,0,114,58,0,0,0,114,136,0,0,0,114,159,0,0, @@ -1569,11 +1569,11 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,0,0,3,0,0,0,8,0,0,0,67,0,0, 0,115,128,0,0,0,116,0,124,0,116,1,116,2,102,2, 131,2,114,36,116,3,160,4,116,5,124,1,131,1,161,1, - 143,12,125,2,124,2,160,6,161,0,87,0,2,0,100,1, + 143,12,125,2,124,2,160,6,161,0,87,0,99,2,100,1, 4,0,4,0,131,3,1,0,83,0,49,0,115,29,119,1, 1,0,1,0,1,0,89,0,1,0,100,1,83,0,116,3, 160,7,124,1,100,2,161,2,143,12,125,2,124,2,160,6, - 161,0,87,0,2,0,100,1,4,0,4,0,131,3,1,0, + 161,0,87,0,99,2,100,1,4,0,4,0,131,3,1,0, 83,0,49,0,115,57,119,1,1,0,1,0,1,0,89,0, 1,0,100,1,83,0,41,3,122,39,82,101,116,117,114,110, 32,116,104,101,32,100,97,116,97,32,102,114,111,109,32,112, @@ -2172,7 +2172,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,9,0,0,0,67,0,0,0,115,76,0,0,0,116,0, 106,1,100,1,117,1,114,14,116,0,106,1,115,14,116,2, 160,3,100,2,116,4,161,2,1,0,116,0,106,1,68,0, - 93,17,125,1,122,7,124,1,124,0,131,1,87,0,2,0, + 93,17,125,1,122,7,124,1,124,0,131,1,87,0,99,2, 1,0,83,0,4,0,116,5,121,37,1,0,1,0,1,0, 89,0,113,17,100,1,83,0,119,0,41,3,122,46,83,101, 97,114,99,104,32,115,121,115,46,112,97,116,104,95,104,111, @@ -2259,7 +2259,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 117,1,114,71,116,4,124,6,100,2,131,2,114,35,124,6, 160,5,124,1,124,3,161,2,125,7,110,6,124,0,160,6, 124,1,124,6,161,2,125,7,124,7,100,1,117,0,114,46, - 113,4,124,7,106,7,100,1,117,1,114,55,124,7,2,0, + 113,4,124,7,106,7,100,1,117,1,114,55,124,7,99,2, 1,0,83,0,124,7,106,8,125,8,124,8,100,1,117,0, 114,66,116,9,100,3,131,1,130,1,124,4,160,10,124,8, 161,1,1,0,113,4,116,11,160,12,124,1,100,1,161,2, @@ -2505,7 +2505,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 124,0,106,14,68,0,93,29,92,2,125,9,125,10,100,5, 124,9,23,0,125,11,116,13,124,8,124,11,131,2,125,12, 116,15,124,12,131,1,114,101,124,0,160,16,124,10,124,1, - 124,12,124,8,103,1,124,2,161,5,2,0,1,0,83,0, + 124,12,124,8,103,1,124,2,161,5,99,2,1,0,83,0, 113,72,116,17,124,8,131,1,125,3,124,0,106,14,68,0, 93,54,92,2,125,9,125,10,122,10,116,13,124,0,106,2, 124,4,124,9,23,0,131,2,125,12,87,0,110,10,4,0, @@ -2513,7 +2513,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 83,0,116,19,106,20,100,7,124,12,100,3,100,8,141,3, 1,0,124,7,124,9,23,0,124,6,118,0,114,163,116,15, 124,12,131,1,114,163,124,0,160,16,124,10,124,1,124,12, - 100,6,124,2,161,5,2,0,1,0,83,0,113,109,124,3, + 100,6,124,2,161,5,99,2,1,0,83,0,113,109,124,3, 114,184,116,19,160,20,100,9,124,8,161,2,1,0,116,19, 160,21,124,1,100,6,161,2,125,13,124,8,103,1,124,13, 95,22,124,13,83,0,100,6,83,0,119,0,119,0,41,10, diff --git a/Python/importlib_zipimport.h b/Python/importlib_zipimport.h index 09a202d8358d68..893ddc1a2d150b 100644 --- a/Python/importlib_zipimport.h +++ b/Python/importlib_zipimport.h @@ -136,7 +136,7 @@ const unsigned char _Py_M__zipimport[] = { 0,89,0,124,7,124,0,95,18,124,1,124,0,95,19,116, 8,106,20,124,3,100,0,100,0,100,8,133,3,25,0,142, 0,124,0,95,21,124,0,106,21,114,141,124,0,4,0,106, - 21,116,7,55,0,2,0,95,21,100,0,83,0,100,0,83, + 21,116,7,55,0,99,2,95,21,100,0,83,0,100,0,83, 0,119,0,119,0,41,9,78,114,0,0,0,0,122,21,97, 114,99,104,105,118,101,32,112,97,116,104,32,105,115,32,101, 109,112,116,121,169,1,218,4,112,97,116,104,84,122,14,110, @@ -605,7 +605,7 @@ const unsigned char _Py_M__zipimport[] = { 0,0,115,56,0,0,0,116,0,124,0,124,1,131,2,125, 2,116,1,68,0,93,18,92,3,125,3,125,4,125,5,124, 2,124,3,23,0,125,6,124,6,124,0,106,2,118,0,114, - 25,124,5,2,0,1,0,83,0,113,7,100,0,83,0,114, + 25,124,5,99,2,1,0,83,0,113,7,100,0,83,0,114, 90,0,0,0,41,3,114,39,0,0,0,218,16,95,122,105, 112,95,115,101,97,114,99,104,111,114,100,101,114,114,28,0, 0,0,41,7,114,32,0,0,0,114,41,0,0,0,114,13, @@ -1013,7 +1013,7 @@ const unsigned char _Py_M__zipimport[] = { 0,125,12,126,12,110,9,100,0,125,12,126,12,119,1,116, 11,124,9,124,10,131,2,125,11,124,11,100,0,117,0,114, 99,113,9,124,8,100,4,25,0,125,9,124,11,124,6,124, - 9,102,3,2,0,1,0,83,0,124,3,114,124,100,5,124, + 9,102,3,99,2,1,0,83,0,124,3,114,124,100,5,124, 3,155,0,157,2,125,13,116,12,124,13,124,1,100,6,141, 2,124,3,130,2,116,12,100,7,124,1,155,2,157,2,124, 1,100,6,141,2,130,1,119,0,119,0,41,8,78,122,13, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index 951f8f8a5569f7..f13c7ba5c93190 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -1,11 +1,11 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&TARGET_POP_TOP, - &&TARGET_ROT_TWO, - &&TARGET_ROT_THREE, + &&_unknown_opcode, + &&_unknown_opcode, &&TARGET_DUP_TOP, &&TARGET_DUP_TOP_TWO, - &&TARGET_ROT_FOUR, + &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, &&TARGET_NOP, @@ -98,7 +98,7 @@ static void *opcode_targets[256] = { &&TARGET_DELETE_ATTR, &&TARGET_STORE_GLOBAL, &&TARGET_DELETE_GLOBAL, - &&TARGET_ROT_N, + &&TARGET_ROTATE, &&TARGET_LOAD_CONST, &&TARGET_LOAD_NAME, &&TARGET_BUILD_TUPLE, From 53cb874b9e977c1002f2a36d131198ad41aa9ef1 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 24 Apr 2021 15:44:02 -0700 Subject: [PATCH 39/47] cleanup_fail_pop always starts a new block --- Python/compile.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Python/compile.c b/Python/compile.c index d8be391584d717..8c37d696ad47eb 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5676,6 +5676,9 @@ cleanup_fail_pop(struct compiler *c, pattern_context *pc) } compiler_use_next_block(c, pc->fail_pop[0]); } + else { + compiler_next_block(c); + } PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; return 1; From 3a4f63e4b2a5ab5d514d3deb8ac802f9c21068dd Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 24 Apr 2021 15:44:08 -0700 Subject: [PATCH 40/47] Cleanup --- Doc/library/dis.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index 3c8cff2ce7771c..a0273d786190c0 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -1237,6 +1237,7 @@ All of the following opcodes use their arguments. .. versionadded:: 3.10 + .. opcode:: ROTATE (count) Lift the top *count* stack items one position up, and move TOS down to From 88975f8e45b2e484ac46949ffaf16baeb00b3c3b Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 24 Apr 2021 16:22:34 -0700 Subject: [PATCH 41/47] Clean up cleanup_fail_pop --- Python/compile.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 8c37d696ad47eb..d48fc4958d3471 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5664,21 +5664,21 @@ jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) static int cleanup_fail_pop(struct compiler *c, pattern_context *pc) { - if (pc->fail_pop_size) { - while (--pc->fail_pop_size) { - compiler_use_next_block(c, pc->fail_pop[pc->fail_pop_size]); - if (!compiler_addop(c, POP_TOP)) { - PyObject_Free(pc->fail_pop); - pc->fail_pop_size = 0; - pc->fail_pop = NULL; - return 0; - } - } - compiler_use_next_block(c, pc->fail_pop[0]); + if (!pc->fail_pop_size) { + assert(pc->fail_pop == NULL); + NEXT_BLOCK(c); + return 1; } - else { - compiler_next_block(c); + while (--pc->fail_pop_size) { + compiler_use_next_block(c, pc->fail_pop[pc->fail_pop_size]); + if (!compiler_addop(c, POP_TOP)) { + pc->fail_pop_size = 0; + PyObject_Free(pc->fail_pop); + pc->fail_pop = NULL; + return 0; + } } + compiler_use_next_block(c, pc->fail_pop[0]); PyObject_Free(pc->fail_pop); pc->fail_pop = NULL; return 1; From 8e25f2679fb11fb916861404e432b2623f7a9886 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 24 Apr 2021 16:41:42 -0700 Subject: [PATCH 42/47] blurb add --- .../Core and Builtins/2021-04-24-16-40-23.bpo-43754.9SzHWG.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-04-24-16-40-23.bpo-43754.9SzHWG.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-04-24-16-40-23.bpo-43754.9SzHWG.rst b/Misc/NEWS.d/next/Core and Builtins/2021-04-24-16-40-23.bpo-43754.9SzHWG.rst new file mode 100644 index 00000000000000..54556fa299814c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-04-24-16-40-23.bpo-43754.9SzHWG.rst @@ -0,0 +1,2 @@ +When performing structural pattern matching (:pep:`634`), captured names are +now left unbound until the *entire* pattern has matched successfully. From 8813dbb2ee3f5fc59064b7cf2f8eec98d01c765a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 29 Apr 2021 18:08:50 -0700 Subject: [PATCH 43/47] Well that wasn't bad at all! --- Python/compile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Python/compile.c b/Python/compile.c index a68da1e5be192f..a5189e8541dc6d 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5924,6 +5924,7 @@ compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) ADDOP_I(c, MATCH_CLASS, nargs); // TOS is now a tuple of (nargs + nattrs) attributes. Preserve it: pc->on_top++; + RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); for (i = 0; i < nargs + nattrs; i++) { pattern_ty pattern; if (i < nargs) { From 2beea3be12b9133e72529573b22d55f6eb6a07e2 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Thu, 29 Apr 2021 21:03:16 -0700 Subject: [PATCH 44/47] Clean up whitespace --- Lib/test/test_patma.py | 1 - Python/compile.c | 23 +---------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index 2ddccab74c2089..8a273be7250bb1 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2865,7 +2865,6 @@ def test_patma_283(self): pass """) - @no_perf def test_patma_284(self): self.assert_syntax_error(""" diff --git a/Python/compile.c b/Python/compile.c index a5189e8541dc6d..ab5a1429c90af2 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5618,7 +5618,6 @@ compiler_slice(struct compiler *c, expr_ty s) // stored *underneath* them on success. This lets us defer all names stores // until the *entire* pattern matches. - #define WILDCARD_CHECK(N) \ ((N)->kind == MatchAs_kind && !(N)->v.MatchAs.name) @@ -5629,7 +5628,6 @@ compiler_slice(struct compiler *c, expr_ty s) #define MATCH_VALUE_EXPR(N) \ ((N)->kind == Constant_kind || (N)->kind == Attribute_kind) - // Allocate or resize pc->fail_pop to allow for n items to be popped on failure. static int ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n) @@ -5653,7 +5651,6 @@ ensure_fail_pop(struct compiler *c, pattern_context *pc, Py_ssize_t n) return 1; } - // Use op to jump to the correct fail_pop block. static int jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) @@ -5667,7 +5664,6 @@ jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) return 1; } - // Build all of the fail_pop blocks and reset fail_pop. static int cleanup_fail_pop(struct compiler *c, pattern_context *pc) @@ -5692,14 +5688,12 @@ cleanup_fail_pop(struct compiler *c, pattern_context *pc) return 1; } - static int compiler_error_duplicate_store(struct compiler *c, identifier n) { return compiler_error(c, "multiple assignments to name %R in pattern", n); } - static int pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) { @@ -5754,7 +5748,6 @@ pattern_unpack_helper(struct compiler *c, asdl_pattern_seq *elts) return 1; } - static int pattern_helper_sequence_unpack(struct compiler *c, asdl_pattern_seq *patterns, Py_ssize_t star, pattern_context *pc) @@ -5773,7 +5766,6 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_pattern_seq *patterns, return 1; } - // Like pattern_helper_sequence_unpack, but uses BINARY_SUBSCR instead of // UNPACK_SEQUENCE / UNPACK_EX. This is more efficient for patterns with a // starred wildcard like [first, *_] / [first, *_, last] / [*_, last] / etc. @@ -5813,7 +5805,6 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_pattern_seq *patterns, return 1; } - // Like compiler_pattern, but turn off checks for irrefutability. static int compiler_pattern_subpattern(struct compiler *c, pattern_ty p, pattern_context *pc) @@ -5825,7 +5816,6 @@ compiler_pattern_subpattern(struct compiler *c, pattern_ty p, pattern_context *p return 1; } - static int compiler_pattern_as(struct compiler *c, pattern_ty p, pattern_context *pc) { @@ -5852,7 +5842,6 @@ compiler_pattern_as(struct compiler *c, pattern_ty p, pattern_context *pc) return 1; } - static int compiler_pattern_star(struct compiler *c, pattern_ty p, pattern_context *pc) { @@ -5861,7 +5850,6 @@ compiler_pattern_star(struct compiler *c, pattern_ty p, pattern_context *pc) return 1; } - static int validate_kwd_attrs(struct compiler *c, asdl_identifier_seq *attrs, asdl_pattern_seq* patterns) { @@ -5886,7 +5874,6 @@ validate_kwd_attrs(struct compiler *c, asdl_identifier_seq *attrs, asdl_pattern_ return 0; } - static int compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) { @@ -5950,7 +5937,6 @@ compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) return 1; } - static int compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) { @@ -6039,7 +6025,6 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) return 1; } - static int compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) { @@ -6240,7 +6225,6 @@ compiler_pattern_sequence(struct compiler *c, pattern_ty p, pattern_context *pc) return 1; } - static int compiler_pattern_value(struct compiler *c, pattern_ty p, pattern_context *pc) { @@ -6256,7 +6240,6 @@ compiler_pattern_value(struct compiler *c, pattern_ty p, pattern_context *pc) return 1; } - static int compiler_pattern_singleton(struct compiler *c, pattern_ty p, pattern_context *pc) { @@ -6267,7 +6250,6 @@ compiler_pattern_singleton(struct compiler *c, pattern_ty p, pattern_context *pc return 1; } - static int compiler_pattern(struct compiler *c, pattern_ty p, pattern_context *pc) { @@ -6296,7 +6278,6 @@ compiler_pattern(struct compiler *c, pattern_ty p, pattern_context *pc) return compiler_error(c, e, p->kind); } - static int compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) { @@ -6368,7 +6349,6 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) return 1; } - static int compiler_match(struct compiler *c, stmt_ty s) { @@ -6379,7 +6359,6 @@ compiler_match(struct compiler *c, stmt_ty s) return result; } - #undef WILDCARD_CHECK #undef WILDCARD_STAR_CHECK @@ -7122,7 +7101,7 @@ fold_tuple_on_constants(struct compiler *c, } -// Eliminate N * ROTATE. +// Eliminate n * ROTATE(n). static void fold_rotations(struct instr *inst, int n) { From 85084b1693ad7b9361aa4aae968b676132f892ac Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 1 May 2021 15:11:34 -0700 Subject: [PATCH 45/47] ROTATE -> ROT_N and add back ROT_* --- Doc/library/dis.rst | 21 ++++++- Include/opcode.h | 5 +- Lib/importlib/_bootstrap_external.py | 2 +- Lib/opcode.py | 5 +- Lib/test/test_peepholer.py | 4 +- Python/ceval.c | 35 ++++++++++- Python/compile.c | 92 ++++++++++++++++++---------- Python/importlib.h | 32 +++++----- Python/importlib_external.h | 16 ++--- Python/importlib_zipimport.h | 6 +- Python/opcode_targets.h | 8 +-- 11 files changed, 157 insertions(+), 69 deletions(-) diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index a0273d786190c0..0491a9d4a072bf 100644 --- a/Doc/library/dis.rst +++ b/Doc/library/dis.rst @@ -333,6 +333,25 @@ The Python compiler currently generates the following bytecode instructions. Removes the top-of-stack (TOS) item. +.. opcode:: ROT_TWO + + Swaps the two top-most stack items. + + +.. opcode:: ROT_THREE + + Lifts second and third stack item one position up, moves top down to position + three. + + +.. opcode:: ROT_FOUR + + Lifts second, third and fourth stack items one position up, moves top down + to position four. + + .. versionadded:: 3.8 + + .. opcode:: DUP_TOP Duplicates the reference on top of the stack. @@ -1238,7 +1257,7 @@ All of the following opcodes use their arguments. .. versionadded:: 3.10 -.. opcode:: ROTATE (count) +.. opcode:: ROT_N (count) Lift the top *count* stack items one position up, and move TOS down to position *count*. diff --git a/Include/opcode.h b/Include/opcode.h index 947c08f8aaab62..52039754bd88ea 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -8,8 +8,11 @@ extern "C" { /* Instruction opcodes for compiled code */ #define POP_TOP 1 +#define ROT_TWO 2 +#define ROT_THREE 3 #define DUP_TOP 4 #define DUP_TOP_TWO 5 +#define ROT_FOUR 6 #define NOP 9 #define UNARY_POSITIVE 10 #define UNARY_NEGATIVE 11 @@ -78,7 +81,7 @@ extern "C" { #define DELETE_ATTR 96 #define STORE_GLOBAL 97 #define DELETE_GLOBAL 98 -#define ROTATE 99 +#define ROT_N 99 #define LOAD_CONST 100 #define LOAD_NAME 101 #define BUILD_TUPLE 102 diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 065f2f96f47c16..9a73c7b43a08cf 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -351,7 +351,7 @@ def _write_atomic(path, data, mode=0o666): # Python 3.10b1 3436 (Add GEN_START bytecode #43683) # Python 3.10b1 3437 (Undo making 'annotations' future by default - We like to dance among core devs!) # Python 3.10b1 3438 Safer line number table handling. -# Python 3.10b1 3439 (replace ROT_* with ROTATE) +# Python 3.10b1 3439 (Add ROT_N) # # MAGIC must change whenever the bytecode emitted by the compiler may no diff --git a/Lib/opcode.py b/Lib/opcode.py index fab9a3b195908b..0d8671395314ab 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -55,9 +55,12 @@ def jabs_op(name, op): # Blank lines correspond to available opcodes def_op('POP_TOP', 1) +def_op('ROT_TWO', 2) +def_op('ROT_THREE', 3) def_op('DUP_TOP', 4) def_op('DUP_TOP_TWO', 5) +def_op('ROT_FOUR', 6) def_op('NOP', 9) def_op('UNARY_POSITIVE', 10) @@ -137,7 +140,7 @@ def jabs_op(name, op): name_op('DELETE_ATTR', 96) # "" name_op('STORE_GLOBAL', 97) # "" name_op('DELETE_GLOBAL', 98) # "" -def_op('ROTATE', 99) +def_op('ROT_N', 99) def_op('LOAD_CONST', 100) # Index in const list hasconst.append(100) name_op('LOAD_NAME', 101) # Index in name list diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py index 61feff360e5c50..4034154e4dcfb5 100644 --- a/Lib/test/test_peepholer.py +++ b/Lib/test/test_peepholer.py @@ -116,8 +116,8 @@ def f(): def test_pack_unpack(self): for line, elem in ( ('a, = a,', 'LOAD_CONST',), - ('a, b = a, b', 'ROTATE',), - ('a, b, c = a, b, c', 'ROTATE',), + ('a, b = a, b', 'ROT_TWO',), + ('a, b, c = a, b, c', 'ROT_THREE',), ): code = compile(line,'','single') self.assertInBytecode(code, elem) diff --git a/Python/ceval.c b/Python/ceval.c index fc1b9032c7ae87..25548e34db246b 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1395,9 +1395,12 @@ eval_frame_handle_pending(PyThreadState *tstate) #define TOP() (stack_pointer[-1]) #define SECOND() (stack_pointer[-2]) #define THIRD() (stack_pointer[-3]) +#define FOURTH() (stack_pointer[-4]) #define PEEK(n) (stack_pointer[-(n)]) #define SET_TOP(v) (stack_pointer[-1] = (v)) #define SET_SECOND(v) (stack_pointer[-2] = (v)) +#define SET_THIRD(v) (stack_pointer[-3] = (v)) +#define SET_FOURTH(v) (stack_pointer[-4] = (v)) #define BASIC_STACKADJ(n) (stack_pointer += n) #define BASIC_PUSH(v) (*stack_pointer++ = (v)) #define BASIC_POP() (*--stack_pointer) @@ -1876,6 +1879,36 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) DISPATCH(); } + case TARGET(ROT_TWO): { + PyObject *top = TOP(); + PyObject *second = SECOND(); + SET_TOP(second); + SET_SECOND(top); + DISPATCH(); + } + + case TARGET(ROT_THREE): { + PyObject *top = TOP(); + PyObject *second = SECOND(); + PyObject *third = THIRD(); + SET_TOP(second); + SET_SECOND(third); + SET_THIRD(top); + DISPATCH(); + } + + case TARGET(ROT_FOUR): { + PyObject *top = TOP(); + PyObject *second = SECOND(); + PyObject *third = THIRD(); + PyObject *fourth = FOURTH(); + SET_TOP(second); + SET_SECOND(third); + SET_THIRD(fourth); + SET_FOURTH(top); + DISPATCH(); + } + case TARGET(DUP_TOP): { PyObject *top = TOP(); Py_INCREF(top); @@ -4366,7 +4399,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) DISPATCH(); } - case TARGET(ROTATE): { + case TARGET(ROT_N): { PyObject *top = TOP(); memmove(&PEEK(oparg - 1), &PEEK(oparg), sizeof(PyObject*) * (oparg - 1)); diff --git a/Python/compile.c b/Python/compile.c index 31257459f43228..813cbfec4f57d5 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -959,6 +959,10 @@ stack_effect(int opcode, int oparg, int jump) /* Stack manipulation */ case POP_TOP: return -1; + case ROT_TWO: + case ROT_THREE: + case ROT_FOUR: + return 0; case DUP_TOP: return 1; case DUP_TOP_TWO: @@ -1204,7 +1208,7 @@ stack_effect(int opcode, int oparg, int jump) return 1; case MATCH_KEYS: return 2; - case ROTATE: + case ROT_N: return 0; default: return PY_INVALID_STACK_EFFECT; @@ -1773,7 +1777,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case FOR_LOOP: /* Pop the iterator */ if (preserve_tos) { - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); } ADDOP(c, POP_TOP); return 1; @@ -1803,13 +1807,13 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case FINALLY_END: if (preserve_tos) { - ADDOP_I(c, ROTATE, 4); + ADDOP(c, ROT_FOUR); } ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); ADDOP(c, POP_TOP); if (preserve_tos) { - ADDOP_I(c, ROTATE, 4); + ADDOP(c, ROT_FOUR); } ADDOP(c, POP_EXCEPT); return 1; @@ -1820,7 +1824,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, SET_LOC(c, (stmt_ty)info->fb_datum); ADDOP(c, POP_BLOCK); if (preserve_tos) { - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); } if(!compiler_call_exit_with_nones(c)) { return 0; @@ -1839,7 +1843,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, ADDOP(c, POP_BLOCK); } if (preserve_tos) { - ADDOP_I(c, ROTATE, 4); + ADDOP(c, ROT_FOUR); } ADDOP(c, POP_EXCEPT); if (info->fb_datum) { @@ -1851,7 +1855,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, case POP_VALUE: if (preserve_tos) { - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); } ADDOP(c, POP_TOP); return 1; @@ -2690,7 +2694,7 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP(c, DUP_TOP); - ADDOP_I(c, ROTATE, 3); + ADDOP(c, ROT_THREE); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_JUMP(c, POP_JUMP_IF_FALSE, cleanup); NEXT_BLOCK(c); @@ -3294,7 +3298,7 @@ compiler_import_as(struct compiler *c, identifier name, identifier asname) if (dot == -1) { break; } - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); ADDOP(c, POP_TOP); } if (!compiler_nameop(c, asname, Store)) { @@ -4072,7 +4076,7 @@ compiler_compare(struct compiler *c, expr_ty e) VISIT(c, expr, (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); ADDOP(c, DUP_TOP); - ADDOP_I(c, ROTATE, 3); + ADDOP(c, ROT_THREE); ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, cleanup); NEXT_BLOCK(c); @@ -4084,7 +4088,7 @@ compiler_compare(struct compiler *c, expr_ty e) return 0; ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); compiler_use_next_block(c, cleanup); - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); ADDOP(c, POP_TOP); compiler_use_next_block(c, end); } @@ -5348,11 +5352,11 @@ compiler_augassign(struct compiler *c, stmt_ty s) switch (e->kind) { case Attribute_kind: c->u->u_lineno = e->end_lineno; - ADDOP_I(c, ROTATE, 2); + ADDOP(c, ROT_TWO); ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); break; case Subscript_kind: - ADDOP_I(c, ROTATE, 3); + ADDOP(c, ROT_THREE); ADDOP(c, STORE_SUBSCR); break; case Name_kind: @@ -5670,7 +5674,7 @@ jump_to_fail_pop(struct compiler *c, pattern_context *pc, int op) // Build all of the fail_pop blocks and reset fail_pop. static int -cleanup_fail_pop(struct compiler *c, pattern_context *pc) +emit_and_reset_fail_pop(struct compiler *c, pattern_context *pc) { if (!pc->fail_pop_size) { assert(pc->fail_pop == NULL); @@ -5719,7 +5723,7 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); if (pc->on_top) { // Rotate this object underneath any items we need to preserve: - ADDOP_I(c, ROTATE, pc->on_top + 1); + ADDOP_I(c, ROT_N, pc->on_top + 1); } return 1; } @@ -6108,7 +6112,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // pc_stores[icontrol:icontrol] = rotate // Do the same thing to the stack, using several rotations: while (istores++ < nstores) { - if (!compiler_addop_i(c, ROTATE, nstores - icontrol)) { + if (!compiler_addop_i(c, ROT_N, nstores - icontrol)) { goto error; } } @@ -6118,7 +6122,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) assert(control); if (!compiler_addop_j(c, JUMP_FORWARD, end) || !compiler_next_block(c) || - !cleanup_fail_pop(c, pc)) + !emit_and_reset_fail_pop(c, pc)) { goto error; } @@ -6157,7 +6161,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // There may also be important items under it that need to be rotated back // up to the top: for (Py_ssize_t i = 0; i < nstores; i++) { - ADDOP_I(c, ROTATE, nstores + pc->on_top + 1); + ADDOP_I(c, ROT_N, nstores + pc->on_top + 1); } // Pop the copy of the subject: ADDOP(c, POP_TOP); @@ -6333,7 +6337,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) } VISIT_SEQ(c, stmt, m->body); ADDOP_JUMP(c, JUMP_FORWARD, end); - RETURN_IF_FALSE(cleanup_fail_pop(c, pc)); + RETURN_IF_FALSE(emit_and_reset_fail_pop(c, pc)); } if (has_default) { if (cases == 1) { @@ -7105,12 +7109,29 @@ fold_tuple_on_constants(struct compiler *c, } -// Eliminate n * ROTATE(n). +// Eliminate n * ROT_N(n). static void fold_rotations(struct instr *inst, int n) { for (int i = 0; i < n; i++) { - if (inst[i].i_opcode != ROTATE || inst[i].i_oparg != n) { + int rot; + switch (inst[i].i_opcode) { + case ROT_N: + rot = inst[i].i_oparg; + break; + case ROT_FOUR: + rot = 4; + break; + case ROT_THREE: + rot = 3; + break; + case ROT_TWO: + rot = 2; + break; + default: + return; + } + if (rot != n) { return; } } @@ -7223,15 +7244,12 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) bb->b_instr[i+1].i_opcode = NOP; break; case 2: - inst->i_opcode = ROTATE; - inst->i_oparg = 2; + inst->i_opcode = ROT_TWO; bb->b_instr[i+1].i_opcode = NOP; break; case 3: - inst->i_opcode = ROTATE; - inst->i_oparg = 3; - bb->b_instr[i+1].i_opcode = ROTATE; - bb->b_instr[i+1].i_oparg = 2; + inst->i_opcode = ROT_THREE; + bb->b_instr[i+1].i_opcode = ROT_TWO; } break; } @@ -7366,11 +7384,23 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) } } break; - case ROTATE: - if (oparg < 2) { - inst->i_opcode = NOP; + case ROT_N: + switch (oparg) { + case 0: + case 1: + inst->i_opcode = NOP; + continue; + case 2: + inst->i_opcode = ROT_TWO; + break; + case 3: + inst->i_opcode = ROT_THREE; + break; + case 4: + inst->i_opcode = ROT_FOUR; + break; } - else if (i >= oparg - 1) { + if (i >= oparg - 1) { fold_rotations(inst - oparg + 1, oparg); } break; diff --git a/Python/importlib.h b/Python/importlib.h index 1e8e8a43de7790..8156973bdeaaf7 100644 --- a/Python/importlib.h +++ b/Python/importlib.h @@ -56,7 +56,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,8, 0,0,0,67,0,0,0,115,38,0,0,0,122,4,124,0, 106,0,87,0,83,0,4,0,116,1,121,18,1,0,1,0, - 1,0,116,2,124,0,131,1,106,0,99,4,89,0,83,0, + 1,0,116,2,124,0,131,1,106,0,6,0,89,0,83,0, 119,0,169,1,78,41,3,218,12,95,95,113,117,97,108,110, 97,109,101,95,95,218,14,65,116,116,114,105,98,117,116,101, 69,114,114,111,114,218,4,116,121,112,101,41,1,218,3,111, @@ -153,11 +153,11 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 116,2,124,1,60,0,122,87,9,0,124,0,106,3,143,64, 1,0,124,0,106,4,100,2,107,2,115,24,124,0,106,5, 124,1,107,2,114,47,124,1,124,0,95,5,124,0,4,0, - 106,4,100,3,55,0,99,2,95,4,9,0,87,0,100,4, + 106,4,100,3,55,0,2,0,95,4,9,0,87,0,100,4, 4,0,4,0,131,3,1,0,87,0,116,2,124,1,61,0, 100,1,83,0,124,0,160,6,161,0,114,57,116,7,100,5, 124,0,22,0,131,1,130,1,124,0,106,8,160,9,100,6, - 161,1,114,70,124,0,4,0,106,10,100,3,55,0,99,2, + 161,1,114,70,124,0,4,0,106,10,100,3,55,0,2,0, 95,10,87,0,100,4,4,0,4,0,131,3,1,0,110,8, 49,0,115,80,119,1,1,0,1,0,1,0,89,0,1,0, 124,0,106,8,160,9,161,0,1,0,124,0,106,8,160,11, @@ -192,9 +192,9 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,160,1,161,0,125,1,124,0,106,2,143,55,1,0,124, 0,106,3,124,1,107,3,114,17,116,4,100,1,131,1,130, 1,124,0,106,5,100,2,107,4,115,24,74,0,130,1,124, - 0,4,0,106,5,100,3,56,0,99,2,95,5,124,0,106, + 0,4,0,106,5,100,3,56,0,2,0,95,5,124,0,106, 5,100,2,107,2,114,54,100,0,124,0,95,3,124,0,106, - 6,114,54,124,0,4,0,106,6,100,3,56,0,99,2,95, + 6,114,54,124,0,4,0,106,6,100,3,56,0,2,0,95, 6,124,0,106,7,160,8,161,0,1,0,87,0,100,0,4, 0,4,0,131,3,1,0,100,0,83,0,49,0,115,65,119, 1,1,0,1,0,1,0,89,0,1,0,100,0,83,0,41, @@ -247,7 +247,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 109,121,77,111,100,117,108,101,76,111,99,107,46,95,95,105, 110,105,116,95,95,99,1,0,0,0,0,0,0,0,0,0, 0,0,1,0,0,0,3,0,0,0,67,0,0,0,115,18, - 0,0,0,124,0,4,0,106,0,100,1,55,0,99,2,95, + 0,0,0,124,0,4,0,106,0,100,1,55,0,2,0,95, 0,100,2,83,0,41,3,78,114,42,0,0,0,84,41,1, 114,30,0,0,0,114,52,0,0,0,114,5,0,0,0,114, 5,0,0,0,114,6,0,0,0,114,43,0,0,0,150,0, @@ -256,8 +256,8 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 113,117,105,114,101,99,1,0,0,0,0,0,0,0,0,0, 0,0,1,0,0,0,3,0,0,0,67,0,0,0,115,36, 0,0,0,124,0,106,0,100,1,107,2,114,9,116,1,100, - 2,131,1,130,1,124,0,4,0,106,0,100,3,56,0,99, - 2,95,0,100,0,83,0,41,4,78,114,25,0,0,0,114, + 2,131,1,130,1,124,0,4,0,106,0,100,3,56,0,2, + 0,95,0,100,0,83,0,41,4,78,114,25,0,0,0,114, 46,0,0,0,114,42,0,0,0,41,2,114,30,0,0,0, 114,47,0,0,0,114,52,0,0,0,114,5,0,0,0,114, 5,0,0,0,114,6,0,0,0,114,44,0,0,0,154,0, @@ -526,8 +526,8 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 110,9,4,0,116,6,121,90,1,0,1,0,1,0,100,5, 125,3,89,0,122,5,124,0,106,7,125,4,87,0,110,25, 4,0,116,6,121,89,1,0,1,0,1,0,124,1,100,2, - 117,0,114,75,100,6,160,8,124,3,161,1,99,4,89,0, - 83,0,100,7,160,8,124,3,124,1,161,2,99,4,89,0, + 117,0,114,75,100,6,160,8,124,3,161,1,6,0,89,0, + 83,0,100,7,160,8,124,3,124,1,161,2,6,0,89,0, 83,0,100,8,160,8,124,3,124,4,161,2,83,0,119,0, 119,0,119,0,41,9,122,44,84,104,101,32,105,109,112,108, 101,109,101,110,116,97,116,105,111,110,32,111,102,32,77,111, @@ -702,7 +702,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 106,3,107,2,111,38,124,2,124,1,106,0,107,2,111,38, 124,0,106,4,124,1,106,4,107,2,111,38,124,0,106,5, 124,1,106,5,107,2,87,0,83,0,4,0,116,6,121,50, - 1,0,1,0,1,0,116,7,99,4,89,0,83,0,119,0, + 1,0,1,0,1,0,116,7,6,0,89,0,83,0,119,0, 114,0,0,0,0,41,8,114,129,0,0,0,114,20,0,0, 0,114,122,0,0,0,114,126,0,0,0,218,6,99,97,99, 104,101,100,218,12,104,97,115,95,108,111,99,97,116,105,111, @@ -1043,7 +1043,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 99,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0, 0,8,0,0,0,67,0,0,0,115,54,0,0,0,116,0, 124,0,106,1,131,1,143,12,1,0,116,2,124,0,131,1, - 87,0,99,2,100,1,4,0,4,0,131,3,1,0,83,0, + 87,0,2,0,100,1,4,0,4,0,131,3,1,0,83,0, 49,0,115,20,119,1,1,0,1,0,1,0,89,0,1,0, 100,1,83,0,41,2,122,191,82,101,116,117,114,110,32,97, 32,110,101,119,32,109,111,100,117,108,101,32,111,98,106,101, @@ -1460,9 +1460,9 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 4,115,131,124,0,116,0,106,6,118,0,114,131,116,0,106, 6,124,0,25,0,125,8,122,5,124,8,106,11,125,9,87, 0,110,12,4,0,116,9,121,138,1,0,1,0,1,0,124, - 7,99,4,89,0,99,2,1,0,83,0,124,9,100,1,117, - 0,114,127,124,7,99,2,1,0,83,0,124,9,99,2,1, - 0,83,0,124,7,99,2,1,0,83,0,113,26,100,1,83, + 7,6,0,89,0,2,0,1,0,83,0,124,9,100,1,117, + 0,114,127,124,7,2,0,1,0,83,0,124,9,2,0,1, + 0,83,0,124,7,2,0,1,0,83,0,113,26,100,1,83, 0,119,0,119,0,41,4,122,21,70,105,110,100,32,97,32, 109,111,100,117,108,101,39,115,32,115,112,101,99,46,78,122, 53,115,121,115,46,109,101,116,97,95,112,97,116,104,32,105, @@ -1562,7 +1562,7 @@ const unsigned char _Py_M__importlib_bootstrap[] = { 0,4,0,0,0,8,0,0,0,67,0,0,0,115,128,0, 0,0,116,0,124,0,131,1,143,31,1,0,116,1,106,2, 160,3,124,0,116,4,161,2,125,2,124,2,116,4,117,0, - 114,28,116,5,124,0,124,1,131,2,87,0,99,2,100,1, + 114,28,116,5,124,0,124,1,131,2,87,0,2,0,100,1, 4,0,4,0,131,3,1,0,83,0,87,0,100,1,4,0, 4,0,131,3,1,0,110,8,49,0,115,38,119,1,1,0, 1,0,1,0,89,0,1,0,124,2,100,1,117,0,114,58, diff --git a/Python/importlib_external.h b/Python/importlib_external.h index 51a6201a4df1f6..8f4eeb0e53483a 100644 --- a/Python/importlib_external.h +++ b/Python/importlib_external.h @@ -1067,7 +1067,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,115,50,0,0,0,122,8,116,0,160,1,116,0,106, 2,124,0,161,2,87,0,83,0,4,0,116,3,121,24,1, 0,1,0,1,0,116,0,160,1,116,0,106,4,124,0,161, - 2,99,4,89,0,83,0,119,0,114,69,0,0,0,41,5, + 2,6,0,89,0,83,0,119,0,114,69,0,0,0,41,5, 218,6,119,105,110,114,101,103,90,7,79,112,101,110,75,101, 121,90,17,72,75,69,89,95,67,85,82,82,69,78,84,95, 85,83,69,82,114,76,0,0,0,90,18,72,75,69,89,95, @@ -1114,7 +1114,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 1,0,1,0,89,0,100,0,83,0,116,3,131,0,68,0, 93,26,92,2,125,5,125,6,124,4,160,4,116,5,124,6, 131,1,161,1,114,56,116,6,106,7,124,1,124,5,124,1, - 124,4,131,2,124,4,100,1,141,3,125,7,124,7,99,2, + 124,4,131,2,124,4,100,1,141,3,125,7,124,7,2,0, 1,0,83,0,113,30,100,0,83,0,119,0,41,2,78,114, 204,0,0,0,41,8,114,223,0,0,0,114,75,0,0,0, 114,76,0,0,0,114,208,0,0,0,114,58,0,0,0,114, @@ -1562,11 +1562,11 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,0,0,0,0,3,0,0,0,8,0,0,0,67,0,0, 0,115,128,0,0,0,116,0,124,0,116,1,116,2,102,2, 131,2,114,36,116,3,160,4,116,5,124,1,131,1,161,1, - 143,12,125,2,124,2,160,6,161,0,87,0,99,2,100,1, + 143,12,125,2,124,2,160,6,161,0,87,0,2,0,100,1, 4,0,4,0,131,3,1,0,83,0,49,0,115,29,119,1, 1,0,1,0,1,0,89,0,1,0,100,1,83,0,116,3, 160,7,124,1,100,2,161,2,143,12,125,2,124,2,160,6, - 161,0,87,0,99,2,100,1,4,0,4,0,131,3,1,0, + 161,0,87,0,2,0,100,1,4,0,4,0,131,3,1,0, 83,0,49,0,115,57,119,1,1,0,1,0,1,0,89,0, 1,0,100,1,83,0,41,3,122,39,82,101,116,117,114,110, 32,116,104,101,32,100,97,116,97,32,102,114,111,109,32,112, @@ -2162,7 +2162,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 0,67,0,0,0,115,76,0,0,0,116,0,106,1,100,1, 117,1,114,14,116,0,106,1,115,14,116,2,160,3,100,2, 116,4,161,2,1,0,116,0,106,1,68,0,93,17,125,1, - 122,7,124,1,124,0,131,1,87,0,99,2,1,0,83,0, + 122,7,124,1,124,0,131,1,87,0,2,0,1,0,83,0, 4,0,116,5,121,37,1,0,1,0,1,0,89,0,113,17, 100,1,83,0,119,0,41,3,122,46,83,101,97,114,99,104, 32,115,121,115,46,112,97,116,104,95,104,111,111,107,115,32, @@ -2249,7 +2249,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 131,2,114,35,124,6,160,5,124,1,124,3,161,2,125,7, 110,6,124,0,160,6,124,1,124,6,161,2,125,7,124,7, 100,1,117,0,114,46,113,4,124,7,106,7,100,1,117,1, - 114,55,124,7,99,2,1,0,83,0,124,7,106,8,125,8, + 114,55,124,7,2,0,1,0,83,0,124,7,106,8,125,8, 124,8,100,1,117,0,114,66,116,9,100,3,131,1,130,1, 124,4,160,10,124,8,161,1,1,0,113,4,116,11,160,12, 124,1,100,1,161,2,125,7,124,4,124,7,95,8,124,7, @@ -2493,7 +2493,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 131,2,125,8,124,0,106,14,68,0,93,29,92,2,125,9, 125,10,100,5,124,9,23,0,125,11,116,13,124,8,124,11, 131,2,125,12,116,15,124,12,131,1,114,101,124,0,160,16, - 124,10,124,1,124,12,124,8,103,1,124,2,161,5,99,2, + 124,10,124,1,124,12,124,8,103,1,124,2,161,5,2,0, 1,0,83,0,113,72,116,17,124,8,131,1,125,3,124,0, 106,14,68,0,93,54,92,2,125,9,125,10,122,10,116,13, 124,0,106,2,124,4,124,9,23,0,131,2,125,12,87,0, @@ -2501,7 +2501,7 @@ const unsigned char _Py_M__importlib_bootstrap_external[] = { 1,0,100,6,83,0,116,19,106,20,100,7,124,12,100,3, 100,8,141,3,1,0,124,7,124,9,23,0,124,6,118,0, 114,163,116,15,124,12,131,1,114,163,124,0,160,16,124,10, - 124,1,124,12,100,6,124,2,161,5,99,2,1,0,83,0, + 124,1,124,12,100,6,124,2,161,5,2,0,1,0,83,0, 113,109,124,3,114,184,116,19,160,20,100,9,124,8,161,2, 1,0,116,19,160,21,124,1,100,6,161,2,125,13,124,8, 103,1,124,13,95,22,124,13,83,0,100,6,83,0,119,0, diff --git a/Python/importlib_zipimport.h b/Python/importlib_zipimport.h index 854e90cd428774..fa00ffc89ea268 100644 --- a/Python/importlib_zipimport.h +++ b/Python/importlib_zipimport.h @@ -136,7 +136,7 @@ const unsigned char _Py_M__zipimport[] = { 0,124,7,124,0,95,18,124,1,124,0,95,19,116,8,106, 20,124,3,100,0,100,0,100,8,133,3,25,0,142,0,124, 0,95,21,124,0,106,21,114,141,124,0,4,0,106,21,116, - 7,55,0,99,2,95,21,100,0,83,0,100,0,83,0,119, + 7,55,0,2,0,95,21,100,0,83,0,100,0,83,0,119, 0,119,0,41,9,78,114,0,0,0,0,122,21,97,114,99, 104,105,118,101,32,112,97,116,104,32,105,115,32,101,109,112, 116,121,169,1,218,4,112,97,116,104,84,122,14,110,111,116, @@ -603,7 +603,7 @@ const unsigned char _Py_M__zipimport[] = { 115,56,0,0,0,116,0,124,0,124,1,131,2,125,2,116, 1,68,0,93,18,92,3,125,3,125,4,125,5,124,2,124, 3,23,0,125,6,124,6,124,0,106,2,118,0,114,25,124, - 5,99,2,1,0,83,0,113,7,100,0,83,0,114,90,0, + 5,2,0,1,0,83,0,113,7,100,0,83,0,114,90,0, 0,0,41,3,114,39,0,0,0,218,16,95,122,105,112,95, 115,101,97,114,99,104,111,114,100,101,114,114,28,0,0,0, 41,7,114,32,0,0,0,114,41,0,0,0,114,13,0,0, @@ -1009,7 +1009,7 @@ const unsigned char _Py_M__zipimport[] = { 12,125,3,87,0,89,0,100,0,125,12,126,12,110,9,100, 0,125,12,126,12,119,1,116,11,124,9,124,10,131,2,125, 11,124,11,100,0,117,0,114,99,113,9,124,8,100,4,25, - 0,125,9,124,11,124,6,124,9,102,3,99,2,1,0,83, + 0,125,9,124,11,124,6,124,9,102,3,2,0,1,0,83, 0,124,3,114,124,100,5,124,3,155,0,157,2,125,13,116, 12,124,13,124,1,100,6,141,2,124,3,130,2,116,12,100, 7,124,1,155,2,157,2,124,1,100,6,141,2,130,1,119, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index f13c7ba5c93190..951f8f8a5569f7 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -1,11 +1,11 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&TARGET_POP_TOP, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_ROT_TWO, + &&TARGET_ROT_THREE, &&TARGET_DUP_TOP, &&TARGET_DUP_TOP_TWO, - &&_unknown_opcode, + &&TARGET_ROT_FOUR, &&_unknown_opcode, &&_unknown_opcode, &&TARGET_NOP, @@ -98,7 +98,7 @@ static void *opcode_targets[256] = { &&TARGET_DELETE_ATTR, &&TARGET_STORE_GLOBAL, &&TARGET_DELETE_GLOBAL, - &&TARGET_ROTATE, + &&TARGET_ROT_N, &&TARGET_LOAD_CONST, &&TARGET_LOAD_NAME, &&TARGET_BUILD_TUPLE, From e818ff3c9526fd406dea64a54ec585909699a14a Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 1 May 2021 15:17:28 -0700 Subject: [PATCH 46/47] Fix whitespace --- Lib/opcode.py | 1 - 1 file changed, 1 deletion(-) diff --git a/Lib/opcode.py b/Lib/opcode.py index 0d8671395314ab..37e88e92df70ec 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -57,7 +57,6 @@ def jabs_op(name, op): def_op('POP_TOP', 1) def_op('ROT_TWO', 2) def_op('ROT_THREE', 3) - def_op('DUP_TOP', 4) def_op('DUP_TOP_TWO', 5) def_op('ROT_FOUR', 6) From 99f0ec6edfdaa10a2bf8c4124ae417d5f6bd4bc6 Mon Sep 17 00:00:00 2001 From: Brandt Bucher Date: Sat, 1 May 2021 19:34:43 -0700 Subject: [PATCH 47/47] Don't store names in reverse order --- Python/compile.c | 72 +++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/Python/compile.c b/Python/compile.c index 813cbfec4f57d5..7cc75ada472c7c 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -5720,12 +5720,9 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) if (duplicate) { return compiler_error_duplicate_store(c, n); } - RETURN_IF_FALSE(!PyList_Append(pc->stores, n)); - if (pc->on_top) { - // Rotate this object underneath any items we need to preserve: - ADDOP_I(c, ROT_N, pc->on_top + 1); - } - return 1; + // Rotate this object underneath any items we need to preserve: + ADDOP_I(c, ROT_N, pc->on_top + PyList_GET_SIZE(pc->stores) + 1); + return !PyList_Append(pc->stores, n); } @@ -6080,7 +6077,8 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) } else if (nstores) { // There were captures. Check to see if we differ from control: - for (Py_ssize_t icontrol = 0; icontrol < nstores; icontrol++) { + Py_ssize_t icontrol = nstores; + while (icontrol--) { PyObject *name = PyList_GET_ITEM(control, icontrol); Py_ssize_t istores = PySequence_Index(pc->stores, name); if (istores < 0) { @@ -6094,25 +6092,27 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) // inefficient when each alternative subpattern binds lots // of names in different orders. It's fine for reasonable // cases, though. - assert(icontrol < istores); + assert(istores < icontrol); + Py_ssize_t rotations = istores + 1; // Perfom the same rotation on pc->stores: - PyObject *rotate = PyList_GetSlice(pc->stores, istores, - nstores); - if (rotate == NULL || - PyList_SetSlice(pc->stores, istores, nstores, NULL) || - PyList_SetSlice(pc->stores, icontrol, icontrol, rotate)) + PyObject *rotated = PyList_GetSlice(pc->stores, 0, + rotations); + if (rotated == NULL || + PyList_SetSlice(pc->stores, 0, rotations, NULL) || + PyList_SetSlice(pc->stores, icontrol - istores, + icontrol - istores, rotated)) { - Py_XDECREF(rotate); + Py_XDECREF(rotated); goto error; } - Py_DECREF(rotate); + Py_DECREF(rotated); // That just did: - // rotate = pc_stores[istores:] - // del pc_stores[istores:] - // pc_stores[icontrol:icontrol] = rotate - // Do the same thing to the stack, using several rotations: - while (istores++ < nstores) { - if (!compiler_addop_i(c, ROT_N, nstores - icontrol)) { + // rotated = pc_stores[:rotations] + // del pc_stores[:rotations] + // pc_stores[icontrol-istores:icontrol-istores] = rotated + // Do the same thing to the stack, using several ROT_Ns: + while (rotations--) { + if (!compiler_addop_i(c, ROT_N, icontrol + 1)) { goto error; } } @@ -6136,10 +6136,22 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) if (!compiler_addop(c, POP_TOP) || !jump_to_fail_pop(c, pc, JUMP_FORWARD)) { goto error; } - // Update the list of previous stores with the names in the control list, - // checking for duplicates: + compiler_use_next_block(c, end); Py_ssize_t nstores = PyList_GET_SIZE(control); + // There's a bunch of stuff on the stack between any where the new stores + // are and where they need to be: + // - The other stores. + // - A copy of the subject. + // - Anything else that may be on top of the stack. + // - Any previous stores we've already stashed away on the stack. + int nrots = nstores + 1 + pc->on_top + PyList_GET_SIZE(pc->stores); for (Py_ssize_t i = 0; i < nstores; i++) { + // Rotate this capture to its proper place on the stack: + if (!compiler_addop_i(c, ROT_N, nrots)) { + goto error; + } + // Update the list of previous stores with this new name, checking for + // duplicates: PyObject *name = PyList_GET_ITEM(control, i); int dupe = PySequence_Contains(pc->stores, name); if (dupe < 0) { @@ -6156,13 +6168,6 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) Py_DECREF(old_pc.stores); Py_DECREF(control); // NOTE: Returning macros are safe again. - compiler_use_next_block(c, end); - // There is a copy of the subject underneath all of the new name stores. - // There may also be important items under it that need to be rotated back - // up to the top: - for (Py_ssize_t i = 0; i < nstores; i++) { - ADDOP_I(c, ROT_N, nstores + pc->on_top + 1); - } // Pop the copy of the subject: ADDOP(c, POP_TOP); return 1; @@ -6315,11 +6320,10 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) return 0; } assert(!pc->on_top); - // It's a match! Store all of the captured names (they're on the stack - // in reverse order). + // It's a match! Store all of the captured names (they're on the stack). Py_ssize_t nstores = PyList_GET_SIZE(pc->stores); - while (nstores--) { - PyObject *name = PyList_GET_ITEM(pc->stores, nstores); + for (Py_ssize_t n = 0; n < nstores; n++) { + PyObject *name = PyList_GET_ITEM(pc->stores, n); if (!compiler_nameop(c, name, Store)) { Py_DECREF(pc->stores); return 0;