[Python-checkins] bpo-46031: add POP_JUMP_IF_NOT_NONE and POP_JUMP_IF_NONE (GH-30019)
markshannon
webhook-mailer at python.org
Thu Jan 6 06:38:40 EST 2022
https://github.com/python/cpython/commit/3db762db72cc0da938614b1e414abb1e12ca4094
commit: 3db762db72cc0da938614b1e414abb1e12ca4094
branch: main
author: penguin_wwy <940375606 at qq.com>
committer: markshannon <mark at hotpy.org>
date: 2022-01-06T11:38:35Z
summary:
bpo-46031: add POP_JUMP_IF_NOT_NONE and POP_JUMP_IF_NONE (GH-30019)
files:
A Misc/NEWS.d/next/Core and Builtins/2021-12-10-09-10-32.bpo-46031.rM7JOX.rst
M Doc/library/dis.rst
M Doc/whatsnew/3.11.rst
M Include/opcode.h
M Lib/importlib/_bootstrap_external.py
M Lib/opcode.py
M Python/ceval.c
M Python/compile.c
M Python/opcode_targets.h
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 8490a09669656..7afa62f95bc64 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -896,6 +896,20 @@ All of the following opcodes use their arguments.
.. versionadded:: 3.11
+.. opcode:: POP_JUMP_IF_NOT_NONE (target)
+
+ If TOS is not none, sets the bytecode counter to *target*. TOS is popped.
+
+ .. versionadded:: 3.11
+
+
+.. opcode:: POP_JUMP_IF_NONE (target)
+
+ If TOS is none, sets the bytecode counter to *target*. TOS is popped.
+
+ .. versionadded:: 3.11
+
+
.. opcode:: PREP_RERAISE_STAR
Combines the raised and reraised exceptions list from TOS, into an exception
diff --git a/Doc/whatsnew/3.11.rst b/Doc/whatsnew/3.11.rst
index 6794e828a7252..98ff2d44a811b 100644
--- a/Doc/whatsnew/3.11.rst
+++ b/Doc/whatsnew/3.11.rst
@@ -398,6 +398,9 @@ CPython bytecode changes
* Added :opcode:`COPY`, which pushes the *i*-th item to the top of the stack.
The item is not removed from its original location.
+* Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to
+ speed up conditional jumps.
+
* :opcode:`JUMP_IF_NOT_EXC_MATCH` no longer pops the active exception.
diff --git a/Include/opcode.h b/Include/opcode.h
index 1af54943e1ca5..e4deeec932cea 100644
--- a/Include/opcode.h
+++ b/Include/opcode.h
@@ -84,6 +84,8 @@ extern "C" {
#define STORE_FAST 125
#define DELETE_FAST 126
#define JUMP_IF_NOT_EG_MATCH 127
+#define POP_JUMP_IF_NOT_NONE 128
+#define POP_JUMP_IF_NONE 129
#define RAISE_VARARGS 130
#define MAKE_FUNCTION 132
#define BUILD_SLICE 133
@@ -162,10 +164,10 @@ extern "C" {
#define STORE_ATTR_SLOT 80
#define STORE_ATTR_WITH_HINT 81
#define LOAD_FAST__LOAD_FAST 87
-#define STORE_FAST__LOAD_FAST 128
-#define LOAD_FAST__LOAD_CONST 129
-#define LOAD_CONST__LOAD_FAST 131
-#define STORE_FAST__STORE_FAST 134
+#define STORE_FAST__LOAD_FAST 131
+#define LOAD_FAST__LOAD_CONST 134
+#define LOAD_CONST__LOAD_FAST 140
+#define STORE_FAST__STORE_FAST 141
#define DO_TRACING 255
#ifdef NEED_OPCODE_JUMP_TABLES
static uint32_t _PyOpcode_RelativeJump[8] = {
@@ -183,7 +185,7 @@ static uint32_t _PyOpcode_Jump[8] = {
0U,
536870912U,
2316288000U,
- 0U,
+ 3U,
0U,
0U,
0U,
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index 872d6d96a74b4..8e21be5916d31 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -378,6 +378,7 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.11a4 3470 (bpo-46221: PREP_RERAISE_STAR no longer pushes lasti)
# Python 3.11a4 3471 (bpo-46202: remove pop POP_EXCEPT_AND_RERAISE)
# Python 3.11a4 3472 (bpo-46009: replace GEN_START with POP_TOP)
+# Python 3.11a4 3473 (Add POP_JUMP_IF_NOT_NONE/POP_JUMP_IF_NONE opcodes)
#
# MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -387,7 +388,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 = (3472).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3473).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 f99e20ad0a670..6030743b35c5b 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -148,9 +148,9 @@ def jabs_op(name, op):
haslocal.append(125)
def_op('DELETE_FAST', 126) # Local variable number
haslocal.append(126)
-
jabs_op('JUMP_IF_NOT_EG_MATCH', 127)
-
+jabs_op('POP_JUMP_IF_NOT_NONE', 128)
+jabs_op('POP_JUMP_IF_NONE', 129)
def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
def_op('MAKE_FUNCTION', 132) # Flags
diff --git a/Misc/NEWS.d/next/Core and Builtins/2021-12-10-09-10-32.bpo-46031.rM7JOX.rst b/Misc/NEWS.d/next/Core and Builtins/2021-12-10-09-10-32.bpo-46031.rM7JOX.rst
new file mode 100644
index 0000000000000..65c8b38cf8acc
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2021-12-10-09-10-32.bpo-46031.rM7JOX.rst
@@ -0,0 +1 @@
+Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to speed up conditional jumps.
\ No newline at end of file
diff --git a/Python/ceval.c b/Python/ceval.c
index b4ac9ec848f77..86d834cd3a67f 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -4049,6 +4049,30 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
DISPATCH();
}
+ TARGET(POP_JUMP_IF_NOT_NONE) {
+ PyObject *value = POP();
+ if (!Py_IsNone(value)) {
+ Py_DECREF(value);
+ JUMPTO(oparg);
+ CHECK_EVAL_BREAKER();
+ DISPATCH();
+ }
+ Py_DECREF(value);
+ DISPATCH();
+ }
+
+ TARGET(POP_JUMP_IF_NONE) {
+ PyObject *value = POP();
+ if (Py_IsNone(value)) {
+ Py_DECREF(value);
+ JUMPTO(oparg);
+ CHECK_EVAL_BREAKER();
+ DISPATCH();
+ }
+ Py_DECREF(value);
+ DISPATCH();
+ }
+
TARGET(JUMP_IF_FALSE_OR_POP) {
PyObject *cond = TOP();
int err;
diff --git a/Python/compile.c b/Python/compile.c
index 3a390751fe2d2..625a07bd39675 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1110,6 +1110,8 @@ stack_effect(int opcode, int oparg, int jump)
case POP_JUMP_IF_FALSE:
case POP_JUMP_IF_TRUE:
+ case POP_JUMP_IF_NONE:
+ case POP_JUMP_IF_NOT_NONE:
return -1;
case LOAD_GLOBAL:
@@ -8519,6 +8521,21 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
bb->b_instr[i+1].i_opcode = NOP;
}
break;
+ case IS_OP:
+ cnt = get_const_value(inst->i_opcode, oparg, consts);
+ if (cnt == NULL) {
+ goto error;
+ }
+ int jump_op = i+2 < bb->b_iused ? bb->b_instr[i+2].i_opcode : 0;
+ if (Py_IsNone(cnt) && (jump_op == POP_JUMP_IF_FALSE || jump_op == POP_JUMP_IF_TRUE)) {
+ unsigned char nextarg = bb->b_instr[i+1].i_oparg;
+ inst->i_opcode = NOP;
+ bb->b_instr[i+1].i_opcode = NOP;
+ bb->b_instr[i+2].i_opcode = nextarg ^ (jump_op == POP_JUMP_IF_FALSE) ?
+ POP_JUMP_IF_NOT_NONE : POP_JUMP_IF_NONE;
+ }
+ Py_DECREF(cnt);
+ break;
}
break;
}
@@ -8611,6 +8628,14 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
break;
}
break;
+ case POP_JUMP_IF_NOT_NONE:
+ case POP_JUMP_IF_NONE:
+ switch (target->i_opcode) {
+ case JUMP_ABSOLUTE:
+ case JUMP_FORWARD:
+ i -= jump_thread(inst, target, inst->i_opcode);
+ }
+ break;
case POP_JUMP_IF_FALSE:
switch (target->i_opcode) {
case JUMP_ABSOLUTE:
@@ -8766,6 +8791,8 @@ normalize_basic_block(basicblock *bb) {
case JUMP_FORWARD:
bb->b_nofallthrough = 1;
/* fall through */
+ case POP_JUMP_IF_NOT_NONE:
+ case POP_JUMP_IF_NONE:
case POP_JUMP_IF_FALSE:
case POP_JUMP_IF_TRUE:
case JUMP_IF_FALSE_OR_POP:
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index e9f1a483b970c..7ba45666ed061 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -127,20 +127,20 @@ static void *opcode_targets[256] = {
&&TARGET_STORE_FAST,
&&TARGET_DELETE_FAST,
&&TARGET_JUMP_IF_NOT_EG_MATCH,
- &&TARGET_STORE_FAST__LOAD_FAST,
- &&TARGET_LOAD_FAST__LOAD_CONST,
+ &&TARGET_POP_JUMP_IF_NOT_NONE,
+ &&TARGET_POP_JUMP_IF_NONE,
&&TARGET_RAISE_VARARGS,
- &&TARGET_LOAD_CONST__LOAD_FAST,
+ &&TARGET_STORE_FAST__LOAD_FAST,
&&TARGET_MAKE_FUNCTION,
&&TARGET_BUILD_SLICE,
- &&TARGET_STORE_FAST__STORE_FAST,
+ &&TARGET_LOAD_FAST__LOAD_CONST,
&&TARGET_MAKE_CELL,
&&TARGET_LOAD_CLOSURE,
&&TARGET_LOAD_DEREF,
&&TARGET_STORE_DEREF,
&&TARGET_DELETE_DEREF,
- &&_unknown_opcode,
- &&_unknown_opcode,
+ &&TARGET_LOAD_CONST__LOAD_FAST,
+ &&TARGET_STORE_FAST__STORE_FAST,
&&TARGET_CALL_FUNCTION_EX,
&&_unknown_opcode,
&&TARGET_EXTENDED_ARG,
More information about the Python-checkins
mailing list