From f9894d5ba0e65e2b34aa4e8628f0e24171ef65c9 Mon Sep 17 00:00:00 2001 From: andychzhang Date: Wed, 22 Sep 2021 22:59:29 +0800 Subject: [PATCH 1/6] bpo-45260: Add superinstruction, UNPACK_SEQUENCE_ST --- Include/opcode.h | 11 +++++----- Lib/opcode.py | 1 + Python/ceval.c | 46 +++++++++++++++++++++++++++++++++++++++++ Python/opcode_targets.h | 10 ++++----- Python/specialize.c | 13 ++++++++++++ 5 files changed, 71 insertions(+), 10 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index 27895255947837..008951a2e461f0 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -162,11 +162,12 @@ extern "C" { #define STORE_ATTR_SPLIT_KEYS 120 #define STORE_ATTR_SLOT 122 #define STORE_ATTR_WITH_HINT 123 -#define LOAD_FAST__LOAD_FAST 127 -#define STORE_FAST__LOAD_FAST 128 -#define LOAD_FAST__LOAD_CONST 134 -#define LOAD_CONST__LOAD_FAST 140 -#define STORE_FAST__STORE_FAST 143 +#define UNPACK_SEQUENCE_ST 127 +#define LOAD_FAST__LOAD_FAST 128 +#define STORE_FAST__LOAD_FAST 134 +#define LOAD_FAST__LOAD_CONST 140 +#define LOAD_CONST__LOAD_FAST 143 +#define STORE_FAST__STORE_FAST 149 #ifdef NEED_OPCODE_JUMP_TABLES static uint32_t _PyOpcode_RelativeJump[8] = { 0U, diff --git a/Lib/opcode.py b/Lib/opcode.py index 5d356746888757..f0ef0ee61bb8b1 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -247,6 +247,7 @@ def jabs_op(name, op): "STORE_ATTR_SLOT", "STORE_ATTR_WITH_HINT", # Super instructions + "UNPACK_SEQUENCE_ST", "LOAD_FAST__LOAD_FAST", "STORE_FAST__LOAD_FAST", "LOAD_FAST__LOAD_CONST", diff --git a/Python/ceval.c b/Python/ceval.c index ab692fd8ded157..f49b50e3702838 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -1723,6 +1723,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ TARGET(LOAD_CLOSURE): TARGET(LOAD_FAST): { + PREDICTED(LOAD_FAST); PyObject *value = GETLOCAL(oparg); if (value == NULL) { goto unbound_local_error; @@ -1748,6 +1749,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr } TARGET(LOAD_FAST__LOAD_FAST): { + PREDICTED(LOAD_FAST__LOAD_FAST); PyObject *value = GETLOCAL(oparg); if (value == NULL) { goto unbound_local_error; @@ -2975,6 +2977,49 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr DISPATCH(); } + TARGET(UNPACK_SEQUENCE_ST): { + PREDICTED(UNPACK_SEQUENCE_ST); + PyObject *seq = POP(), *item, **items; + if (PyTuple_CheckExact(seq) && + PyTuple_GET_SIZE(seq) == oparg) { + items = ((PyTupleObject *)seq)->ob_item; + int i = -1, next_oparg; + while (++i < oparg) { + item = items[i]; + Py_INCREF(item); + next_oparg= _Py_OPARG(*(next_instr++)); + SETLOCAL(next_oparg, item); + } + } else if (PyList_CheckExact(seq) && + PyList_GET_SIZE(seq) == oparg) { + items = ((PyListObject *)seq)->ob_item; + int i = -1, next_oparg; + while (++i < oparg) { + item = items[i]; + Py_INCREF(item); + next_oparg= _Py_OPARG(*(next_instr++)); + SETLOCAL(next_oparg, item); + } + } else if (unpack_iterable(tstate, seq, oparg, -1, + stack_pointer + oparg)) { + items = stack_pointer + oparg - 1; + int i = -1, next_oparg; + while (++i < oparg) { + item = *(items - i); + next_oparg= _Py_OPARG(*(next_instr++)); + SETLOCAL(next_oparg, item); + } + } else { + /* unpack_iterable() raised an exception */ + Py_DECREF(seq); + goto error; + } + Py_DECREF(seq); + PREDICT(LOAD_FAST__LOAD_FAST); + PREDICT(LOAD_FAST); + NOTRACE_DISPATCH(); + } + TARGET(UNPACK_EX): { int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8); PyObject *seq = POP(); @@ -4242,6 +4287,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr if (next != NULL) { PUSH(next); PREDICT(STORE_FAST); + PREDICT(UNPACK_SEQUENCE_ST); PREDICT(UNPACK_SEQUENCE); DISPATCH(); } diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index f3bfae545bcd48..a1a8263f50aa5e 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -126,29 +126,29 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_FAST, &&TARGET_STORE_FAST, &&TARGET_DELETE_FAST, + &&TARGET_UNPACK_SEQUENCE_ST, &&TARGET_LOAD_FAST__LOAD_FAST, - &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_GEN_START, &&TARGET_RAISE_VARARGS, &&TARGET_CALL_FUNCTION, &&TARGET_MAKE_FUNCTION, &&TARGET_BUILD_SLICE, - &&TARGET_LOAD_FAST__LOAD_CONST, + &&TARGET_STORE_FAST__LOAD_FAST, &&TARGET_MAKE_CELL, &&TARGET_LOAD_CLOSURE, &&TARGET_LOAD_DEREF, &&TARGET_STORE_DEREF, &&TARGET_DELETE_DEREF, - &&TARGET_LOAD_CONST__LOAD_FAST, + &&TARGET_LOAD_FAST__LOAD_CONST, &&TARGET_CALL_FUNCTION_KW, &&TARGET_CALL_FUNCTION_EX, - &&TARGET_STORE_FAST__STORE_FAST, + &&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_EXTENDED_ARG, &&TARGET_LIST_APPEND, &&TARGET_SET_ADD, &&TARGET_MAP_ADD, &&TARGET_LOAD_CLASSDEREF, - &&_unknown_opcode, + &&TARGET_STORE_FAST__STORE_FAST, &&_unknown_opcode, &&_unknown_opcode, &&TARGET_MATCH_CLASS, diff --git a/Python/specialize.c b/Python/specialize.c index 1ab79bf3ea0c5d..e3514418ee5743 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -344,6 +344,19 @@ optimize(SpecializedCacheOrInstruction *quickened, int len) /* Super instructions don't use the cache, * so no need to update the offset. */ switch (opcode) { + case UNPACK_SEQUENCE: { + int j = 1; + for (; j <= oparg; ++j) { + if (_Py_OPCODE(instructions[i+j]) != STORE_FAST) { + break; + } + } + if (j == (oparg+1)) { + instructions[i] = _Py_MAKECODEUNIT(UNPACK_SEQUENCE_ST, oparg); + i += oparg; + } + break; + } case JUMP_ABSOLUTE: instructions[i] = _Py_MAKECODEUNIT(JUMP_ABSOLUTE_QUICK, oparg); break; From b64d6f499b124bcd7342671d8bf5a374597718b2 Mon Sep 17 00:00:00 2001 From: andychzhang Date: Tue, 28 Sep 2021 12:02:49 +0800 Subject: [PATCH 2/6] bpo-45260: Add superinstruction, UNPACK_SEQUENCE_ST --- Include/opcode.h | 2 +- Lib/opcode.py | 2 +- Python/ceval.c | 6 +++--- Python/opcode_targets.h | 2 +- Python/specialize.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index 008951a2e461f0..2fa257fb90b085 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -162,7 +162,7 @@ extern "C" { #define STORE_ATTR_SPLIT_KEYS 120 #define STORE_ATTR_SLOT 122 #define STORE_ATTR_WITH_HINT 123 -#define UNPACK_SEQUENCE_ST 127 +#define UNPACK_SEQUENCE__STORE_FAST 127 #define LOAD_FAST__LOAD_FAST 128 #define STORE_FAST__LOAD_FAST 134 #define LOAD_FAST__LOAD_CONST 140 diff --git a/Lib/opcode.py b/Lib/opcode.py index f0ef0ee61bb8b1..39279986b9d043 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -247,7 +247,7 @@ def jabs_op(name, op): "STORE_ATTR_SLOT", "STORE_ATTR_WITH_HINT", # Super instructions - "UNPACK_SEQUENCE_ST", + "UNPACK_SEQUENCE__STORE_FAST", "LOAD_FAST__LOAD_FAST", "STORE_FAST__LOAD_FAST", "LOAD_FAST__LOAD_CONST", diff --git a/Python/ceval.c b/Python/ceval.c index f49b50e3702838..e8baafba727640 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2977,8 +2977,8 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr DISPATCH(); } - TARGET(UNPACK_SEQUENCE_ST): { - PREDICTED(UNPACK_SEQUENCE_ST); + TARGET(UNPACK_SEQUENCE__STORE_FAST): { + PREDICTED(UNPACK_SEQUENCE__STORE_FAST); PyObject *seq = POP(), *item, **items; if (PyTuple_CheckExact(seq) && PyTuple_GET_SIZE(seq) == oparg) { @@ -4287,7 +4287,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr if (next != NULL) { PUSH(next); PREDICT(STORE_FAST); - PREDICT(UNPACK_SEQUENCE_ST); + PREDICT(UNPACK_SEQUENCE__STORE_FAST); PREDICT(UNPACK_SEQUENCE); DISPATCH(); } diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index a1a8263f50aa5e..2b8a5f91c99d7b 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -126,7 +126,7 @@ static void *opcode_targets[256] = { &&TARGET_LOAD_FAST, &&TARGET_STORE_FAST, &&TARGET_DELETE_FAST, - &&TARGET_UNPACK_SEQUENCE_ST, + &&TARGET_UNPACK_SEQUENCE__STORE_FAST, &&TARGET_LOAD_FAST__LOAD_FAST, &&TARGET_GEN_START, &&TARGET_RAISE_VARARGS, diff --git a/Python/specialize.c b/Python/specialize.c index e3514418ee5743..4f744dae1966e4 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -352,7 +352,7 @@ optimize(SpecializedCacheOrInstruction *quickened, int len) } } if (j == (oparg+1)) { - instructions[i] = _Py_MAKECODEUNIT(UNPACK_SEQUENCE_ST, oparg); + instructions[i] = _Py_MAKECODEUNIT(UNPACK_SEQUENCE__STORE_FAST, oparg); i += oparg; } break; From 6986c390631787ec23c7d0137e9453f6bf0a107b Mon Sep 17 00:00:00 2001 From: andychzhang Date: Wed, 29 Sep 2021 11:06:30 +0800 Subject: [PATCH 3/6] bpo-45260: Add superinstruction, UNPACK_SEQUENCE__STORE_FAST, implement in compiler --- Include/opcode.h | 2 +- Lib/opcode.py | 2 +- Lib/test/test_dis.py | 3 ++- Lib/test/test_sys_settrace.py | 4 ++-- Python/compile.c | 31 +++++++++++++++++++++++++++++++ Python/specialize.c | 13 ++----------- 6 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Include/opcode.h b/Include/opcode.h index 2fa257fb90b085..72a3f0080e59b4 100644 --- a/Include/opcode.h +++ b/Include/opcode.h @@ -108,6 +108,7 @@ extern "C" { #define LOAD_FAST 124 #define STORE_FAST 125 #define DELETE_FAST 126 +#define UNPACK_SEQUENCE__STORE_FAST 127 #define GEN_START 129 #define RAISE_VARARGS 130 #define CALL_FUNCTION 131 @@ -162,7 +163,6 @@ extern "C" { #define STORE_ATTR_SPLIT_KEYS 120 #define STORE_ATTR_SLOT 122 #define STORE_ATTR_WITH_HINT 123 -#define UNPACK_SEQUENCE__STORE_FAST 127 #define LOAD_FAST__LOAD_FAST 128 #define STORE_FAST__LOAD_FAST 134 #define LOAD_FAST__LOAD_CONST 140 diff --git a/Lib/opcode.py b/Lib/opcode.py index 39279986b9d043..2a0069faff4a7c 100644 --- a/Lib/opcode.py +++ b/Lib/opcode.py @@ -174,6 +174,7 @@ def jabs_op(name, op): haslocal.append(125) def_op('DELETE_FAST', 126) # Local variable number haslocal.append(126) +def_op('UNPACK_SEQUENCE__STORE_FAST', 127) def_op('GEN_START', 129) # Kind of generator/coroutine def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) @@ -247,7 +248,6 @@ def jabs_op(name, op): "STORE_ATTR_SLOT", "STORE_ATTR_WITH_HINT", # Super instructions - "UNPACK_SEQUENCE__STORE_FAST", "LOAD_FAST__LOAD_FAST", "STORE_FAST__LOAD_FAST", "LOAD_FAST__LOAD_CONST", diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py index 0899db66d82410..8b62d19ac9f320 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -522,7 +522,8 @@ def test_widths(self): for opcode, opname in enumerate(dis.opname): if opname in ('BUILD_MAP_UNPACK_WITH_CALL', 'BUILD_TUPLE_UNPACK_WITH_CALL', - 'JUMP_IF_NOT_EXC_MATCH'): + 'JUMP_IF_NOT_EXC_MATCH', + 'UNPACK_SEQUENCE__STORE_FAST'): continue with self.subTest(opname=opname): width = dis._OPNAME_WIDTH diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 3fe0bb7f460b9a..8f5fa97a8f397f 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -723,7 +723,7 @@ def func(): self.run_and_compare(func, [(0, 'call'), (1, 'line'), - (2, 'line'), + #(2, 'line'), (3, 'line'), (4, 'line'), (5, 'line'), @@ -759,7 +759,7 @@ def func(): self.run_and_compare(func, [(0, 'call'), (1, 'line'), - (2, 'line'), + #(2, 'line'), (3, 'line'), (4, 'line'), (5, 'line'), diff --git a/Python/compile.c b/Python/compile.c index fdc2ce61a8e035..b77e4f307ef13e 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1092,6 +1092,7 @@ stack_effect(int opcode, int oparg, int jump) case DELETE_NAME: return 0; case UNPACK_SEQUENCE: + case UNPACK_SEQUENCE__STORE_FAST: return oparg-1; case UNPACK_EX: return (oparg&0xFF) + (oparg>>8); @@ -4009,10 +4010,25 @@ assignment_helper(struct compiler *c, asdl_expr_seq *elts) { Py_ssize_t n = asdl_seq_LEN(elts); RETURN_IF_FALSE(unpack_helper(c, elts)); + basicblock *bb = c->u->u_curblock; + int idx = bb->b_iused-1; for (Py_ssize_t i = 0; i < n; i++) { expr_ty elt = asdl_seq_GET(elts, i); VISIT(c, expr, elt->kind != Starred_kind ? elt : elt->v.Starred.value); } + struct instr *stmt = &bb->b_instr[idx]; + if (stmt->i_opcode == UNPACK_SEQUENCE) { + int count = stmt->i_oparg; + int i = 1; + for (; i <= count; ++i) { + if ((stmt + i)->i_opcode != STORE_FAST) { + break; + } + } + if (i > count) { + stmt->i_opcode = UNPACK_SEQUENCE__STORE_FAST; + } + } return 1; } @@ -5962,6 +5978,8 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_pattern_seq *patterns, Py_ssize_t star, pattern_context *pc) { RETURN_IF_FALSE(pattern_unpack_helper(c, patterns)); + basicblock *bb = c->u->u_curblock; + int idx = bb->b_iused-1; Py_ssize_t size = asdl_seq_LEN(patterns); // We've now got a bunch of new subjects on the stack. They need to remain // there after each subpattern match: @@ -5972,6 +5990,19 @@ pattern_helper_sequence_unpack(struct compiler *c, asdl_pattern_seq *patterns, pattern_ty pattern = asdl_seq_GET(patterns, i); RETURN_IF_FALSE(compiler_pattern_subpattern(c, pattern, pc)); } + struct instr *stmt = &bb->b_instr[idx]; + if (stmt->i_opcode == UNPACK_SEQUENCE) { + int count = stmt->i_oparg; + int i = 1; + for (; i <= count; ++i) { + if ((stmt + i)->i_opcode != STORE_FAST) { + break; + } + } + if (i > count) { + stmt->i_opcode = UNPACK_SEQUENCE__STORE_FAST; + } + } return 1; } diff --git a/Python/specialize.c b/Python/specialize.c index 4f744dae1966e4..096a8116976f0b 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -344,17 +344,8 @@ optimize(SpecializedCacheOrInstruction *quickened, int len) /* Super instructions don't use the cache, * so no need to update the offset. */ switch (opcode) { - case UNPACK_SEQUENCE: { - int j = 1; - for (; j <= oparg; ++j) { - if (_Py_OPCODE(instructions[i+j]) != STORE_FAST) { - break; - } - } - if (j == (oparg+1)) { - instructions[i] = _Py_MAKECODEUNIT(UNPACK_SEQUENCE__STORE_FAST, oparg); - i += oparg; - } + case UNPACK_SEQUENCE__STORE_FAST: { + i += oparg; break; } case JUMP_ABSOLUTE: From 880ab138b935ce046e24ac1d7af557054f12dcb8 Mon Sep 17 00:00:00 2001 From: andychzhang Date: Sat, 9 Oct 2021 10:53:15 +0800 Subject: [PATCH 4/6] bpo-45260: Add superinstruction, UNPACK_SEQUENCE__STORE_FAST --- Python/ceval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/ceval.c b/Python/ceval.c index abe375852edfdf..008d67189a23c4 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -3004,7 +3004,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr Py_DECREF(seq); PREDICT(LOAD_FAST__LOAD_FAST); PREDICT(LOAD_FAST); - NOTRACE_DISPATCH(); + DISPATCH(); } TARGET(UNPACK_EX) { From ac66a60a68ea55e805eb36aa14190257fa556f84 Mon Sep 17 00:00:00 2001 From: andychzhang Date: Sat, 9 Oct 2021 11:27:21 +0800 Subject: [PATCH 5/6] bpo-45260: Add superinstruction, UNPACK_SEQUENCE__STORE_FAST --- Lib/test/test_sys_settrace.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py index 8f5fa97a8f397f..3fe0bb7f460b9a 100644 --- a/Lib/test/test_sys_settrace.py +++ b/Lib/test/test_sys_settrace.py @@ -723,7 +723,7 @@ def func(): self.run_and_compare(func, [(0, 'call'), (1, 'line'), - #(2, 'line'), + (2, 'line'), (3, 'line'), (4, 'line'), (5, 'line'), @@ -759,7 +759,7 @@ def func(): self.run_and_compare(func, [(0, 'call'), (1, 'line'), - #(2, 'line'), + (2, 'line'), (3, 'line'), (4, 'line'), (5, 'line'), From 39890657167b2816d1a755a66a34504be60ea473 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sat, 9 Oct 2021 03:52:11 +0000 Subject: [PATCH 6/6] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Core and Builtins/2021-10-09-03-52-11.bpo-45260.lLIZZy.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2021-10-09-03-52-11.bpo-45260.lLIZZy.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-10-09-03-52-11.bpo-45260.lLIZZy.rst b/Misc/NEWS.d/next/Core and Builtins/2021-10-09-03-52-11.bpo-45260.lLIZZy.rst new file mode 100644 index 00000000000000..a868efc6b5ef9b --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2021-10-09-03-52-11.bpo-45260.lLIZZy.rst @@ -0,0 +1 @@ +Add superinstruction UNPACK_SEQUENCE__STORE_FAST using the PEP 659 machinery. \ No newline at end of file