Skip to content

Commit 3db762d

Browse files
authored
bpo-46031: add POP_JUMP_IF_NOT_NONE and POP_JUMP_IF_NONE (GH-30019)
1 parent 35d6540 commit 3db762d

File tree

9 files changed

+86
-14
lines changed

9 files changed

+86
-14
lines changed

Doc/library/dis.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,20 @@ All of the following opcodes use their arguments.
896896
.. versionadded:: 3.11
897897

898898

899+
.. opcode:: POP_JUMP_IF_NOT_NONE (target)
900+
901+
If TOS is not none, sets the bytecode counter to *target*. TOS is popped.
902+
903+
.. versionadded:: 3.11
904+
905+
906+
.. opcode:: POP_JUMP_IF_NONE (target)
907+
908+
If TOS is none, sets the bytecode counter to *target*. TOS is popped.
909+
910+
.. versionadded:: 3.11
911+
912+
899913
.. opcode:: PREP_RERAISE_STAR
900914

901915
Combines the raised and reraised exceptions list from TOS, into an exception

Doc/whatsnew/3.11.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,9 @@ CPython bytecode changes
398398
* Added :opcode:`COPY`, which pushes the *i*-th item to the top of the stack.
399399
The item is not removed from its original location.
400400

401+
* Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to
402+
speed up conditional jumps.
403+
401404
* :opcode:`JUMP_IF_NOT_EXC_MATCH` no longer pops the active exception.
402405

403406

Include/opcode.h

Lines changed: 7 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,7 @@ def _write_atomic(path, data, mode=0o666):
378378
# Python 3.11a4 3470 (bpo-46221: PREP_RERAISE_STAR no longer pushes lasti)
379379
# Python 3.11a4 3471 (bpo-46202: remove pop POP_EXCEPT_AND_RERAISE)
380380
# Python 3.11a4 3472 (bpo-46009: replace GEN_START with POP_TOP)
381+
# Python 3.11a4 3473 (Add POP_JUMP_IF_NOT_NONE/POP_JUMP_IF_NONE opcodes)
381382

382383
#
383384
# MAGIC must change whenever the bytecode emitted by the compiler may no
@@ -387,7 +388,7 @@ def _write_atomic(path, data, mode=0o666):
387388
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
388389
# in PC/launcher.c must also be updated.
389390

390-
MAGIC_NUMBER = (3472).to_bytes(2, 'little') + b'\r\n'
391+
MAGIC_NUMBER = (3473).to_bytes(2, 'little') + b'\r\n'
391392
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
392393

393394
_PYCACHE = '__pycache__'

Lib/opcode.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,9 +148,9 @@ def jabs_op(name, op):
148148
haslocal.append(125)
149149
def_op('DELETE_FAST', 126) # Local variable number
150150
haslocal.append(126)
151-
152151
jabs_op('JUMP_IF_NOT_EG_MATCH', 127)
153-
152+
jabs_op('POP_JUMP_IF_NOT_NONE', 128)
153+
jabs_op('POP_JUMP_IF_NONE', 129)
154154
def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
155155

156156
def_op('MAKE_FUNCTION', 132) # Flags
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to speed up conditional jumps.

Python/ceval.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4049,6 +4049,30 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
40494049
DISPATCH();
40504050
}
40514051

4052+
TARGET(POP_JUMP_IF_NOT_NONE) {
4053+
PyObject *value = POP();
4054+
if (!Py_IsNone(value)) {
4055+
Py_DECREF(value);
4056+
JUMPTO(oparg);
4057+
CHECK_EVAL_BREAKER();
4058+
DISPATCH();
4059+
}
4060+
Py_DECREF(value);
4061+
DISPATCH();
4062+
}
4063+
4064+
TARGET(POP_JUMP_IF_NONE) {
4065+
PyObject *value = POP();
4066+
if (Py_IsNone(value)) {
4067+
Py_DECREF(value);
4068+
JUMPTO(oparg);
4069+
CHECK_EVAL_BREAKER();
4070+
DISPATCH();
4071+
}
4072+
Py_DECREF(value);
4073+
DISPATCH();
4074+
}
4075+
40524076
TARGET(JUMP_IF_FALSE_OR_POP) {
40534077
PyObject *cond = TOP();
40544078
int err;

Python/compile.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1110,6 +1110,8 @@ stack_effect(int opcode, int oparg, int jump)
11101110

11111111
case POP_JUMP_IF_FALSE:
11121112
case POP_JUMP_IF_TRUE:
1113+
case POP_JUMP_IF_NONE:
1114+
case POP_JUMP_IF_NOT_NONE:
11131115
return -1;
11141116

11151117
case LOAD_GLOBAL:
@@ -8519,6 +8521,21 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
85198521
bb->b_instr[i+1].i_opcode = NOP;
85208522
}
85218523
break;
8524+
case IS_OP:
8525+
cnt = get_const_value(inst->i_opcode, oparg, consts);
8526+
if (cnt == NULL) {
8527+
goto error;
8528+
}
8529+
int jump_op = i+2 < bb->b_iused ? bb->b_instr[i+2].i_opcode : 0;
8530+
if (Py_IsNone(cnt) && (jump_op == POP_JUMP_IF_FALSE || jump_op == POP_JUMP_IF_TRUE)) {
8531+
unsigned char nextarg = bb->b_instr[i+1].i_oparg;
8532+
inst->i_opcode = NOP;
8533+
bb->b_instr[i+1].i_opcode = NOP;
8534+
bb->b_instr[i+2].i_opcode = nextarg ^ (jump_op == POP_JUMP_IF_FALSE) ?
8535+
POP_JUMP_IF_NOT_NONE : POP_JUMP_IF_NONE;
8536+
}
8537+
Py_DECREF(cnt);
8538+
break;
85228539
}
85238540
break;
85248541
}
@@ -8611,6 +8628,14 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts)
86118628
break;
86128629
}
86138630
break;
8631+
case POP_JUMP_IF_NOT_NONE:
8632+
case POP_JUMP_IF_NONE:
8633+
switch (target->i_opcode) {
8634+
case JUMP_ABSOLUTE:
8635+
case JUMP_FORWARD:
8636+
i -= jump_thread(inst, target, inst->i_opcode);
8637+
}
8638+
break;
86148639
case POP_JUMP_IF_FALSE:
86158640
switch (target->i_opcode) {
86168641
case JUMP_ABSOLUTE:
@@ -8766,6 +8791,8 @@ normalize_basic_block(basicblock *bb) {
87668791
case JUMP_FORWARD:
87678792
bb->b_nofallthrough = 1;
87688793
/* fall through */
8794+
case POP_JUMP_IF_NOT_NONE:
8795+
case POP_JUMP_IF_NONE:
87698796
case POP_JUMP_IF_FALSE:
87708797
case POP_JUMP_IF_TRUE:
87718798
case JUMP_IF_FALSE_OR_POP:

Python/opcode_targets.h

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)