diff --git a/Include/opcode.h b/Include/opcode.h index 27895255947837..dfe2dae38f27c8 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_ST 127 #define GEN_START 129 #define RAISE_VARARGS 130 #define CALL_FUNCTION 131 @@ -162,11 +163,11 @@ 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 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..e7d92b24967070 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_ST', 127) def_op('GEN_START', 129) # Kind of generator/coroutine def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) 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/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/compile.c b/Python/compile.c index fdc2ce61a8e035..5c444d5b5ee130 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_ST: 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_ST; + } + } 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_ST; + } + } return 1; } 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..1ee9cbced47796 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -344,6 +344,10 @@ optimize(SpecializedCacheOrInstruction *quickened, int len) /* Super instructions don't use the cache, * so no need to update the offset. */ switch (opcode) { + case UNPACK_SEQUENCE_ST: { + i += oparg; + break; + } case JUMP_ABSOLUTE: instructions[i] = _Py_MAKECODEUNIT(JUMP_ABSOLUTE_QUICK, oparg); break;