Skip to content

Commit 8548366

Browse files
authored
bpo-46528: Simplify the VM's stack manipulations (GH-30902)
1 parent d4a85f1 commit 8548366

File tree

12 files changed

+285
-320
lines changed

12 files changed

+285
-320
lines changed

Doc/library/dis.rst

+9-45
Original file line numberDiff line numberDiff line change
@@ -348,46 +348,28 @@ The Python compiler currently generates the following bytecode instructions.
348348

349349
.. opcode:: NOP
350350

351-
Do nothing code. Used as a placeholder by the bytecode optimizer.
351+
Do nothing code. Used as a placeholder by the bytecode optimizer, and to
352+
generate line tracing events.
352353

353354

354355
.. opcode:: POP_TOP
355356

356357
Removes the top-of-stack (TOS) item.
357358

358359

359-
.. opcode:: ROT_TWO
360-
361-
Swaps the two top-most stack items.
362-
363-
364-
.. opcode:: ROT_THREE
365-
366-
Lifts second and third stack item one position up, moves top down to position
367-
three.
368-
369-
370-
.. opcode:: ROT_FOUR
371-
372-
Lifts second, third and fourth stack items one position up, moves top down
373-
to position four.
374-
375-
.. versionadded:: 3.8
376-
377-
378-
.. opcode:: DUP_TOP
360+
.. opcode:: COPY (i)
379361

380-
Duplicates the reference on top of the stack.
362+
Push the *i*-th item to the top of the stack. The item is not removed from its
363+
original location.
381364

382-
.. versionadded:: 3.2
365+
.. versionadded:: 3.11
383366

384367

385-
.. opcode:: DUP_TOP_TWO
368+
.. opcode:: SWAP (i)
386369

387-
Duplicates the two references on top of the stack, leaving them in the
388-
same order.
370+
Swap TOS with the item at position *i*.
389371

390-
.. versionadded:: 3.2
372+
.. versionadded:: 3.11
391373

392374

393375
**Unary operations**
@@ -689,8 +671,6 @@ iterations of the loop.
689671
success (``True``) or failure (``False``).
690672

691673

692-
All of the following opcodes use their arguments.
693-
694674
.. opcode:: STORE_NAME (namei)
695675

696676
Implements ``name = TOS``. *namei* is the index of *name* in the attribute
@@ -1217,22 +1197,6 @@ All of the following opcodes use their arguments.
12171197
success (``True``) or failure (``False``).
12181198

12191199

1220-
.. opcode:: ROT_N (count)
1221-
1222-
Lift the top *count* stack items one position up, and move TOS down to
1223-
position *count*.
1224-
1225-
.. versionadded:: 3.10
1226-
1227-
1228-
.. opcode:: COPY (i)
1229-
1230-
Push the *i*-th item to the top of the stack. The item is not removed from its
1231-
original location.
1232-
1233-
.. versionadded:: 3.11
1234-
1235-
12361200
.. opcode:: RESUME (where)
12371201

12381202
A no-op. Performs internal tracing, debugging and optimization checks.

Doc/whatsnew/3.11.rst

+3-2
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,9 @@ CPython bytecode changes
411411
indicate failure with :const:`None` (where a tuple of extracted values would
412412
otherwise be).
413413

414-
* Added :opcode:`COPY`, which pushes the *i*-th item to the top of the stack.
415-
The item is not removed from its original location.
414+
* Replace several stack manipulation instructions (``DUP_TOP``, ``DUP_TOP_TWO``,
415+
``ROT_TWO``, ``ROT_THREE``, ``ROT_FOUR``, and ``ROT_N``) with new
416+
:opcode:`COPY` and :opcode:`SWAP` instructions.
416417

417418
* Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to
418419
speed up conditional jumps.

Include/opcode.h

+56-61
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/importlib/_bootstrap_external.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,8 @@ def _write_atomic(path, data, mode=0o666):
382382
# Python 3.11a4 3474 (Add RESUME opcode)
383383
# Python 3.11a5 3475 (Add RETURN_GENERATOR opcode)
384384
# Python 3.11a5 3476 (Add ASYNC_GEN_WRAP opcode)
385+
# Python 3.11a5 3477 (Replace DUP_TOP/DUP_TOP_TWO with COPY and
386+
# ROT_TWO/ROT_THREE/ROT_FOUR/ROT_N with SWAP)
385387

386388
# Python 3.12 will start with magic number 3500
387389

@@ -395,7 +397,7 @@ def _write_atomic(path, data, mode=0o666):
395397
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
396398
# in PC/launcher.c must also be updated.
397399

398-
MAGIC_NUMBER = (3476).to_bytes(2, 'little') + b'\r\n'
400+
MAGIC_NUMBER = (3477).to_bytes(2, 'little') + b'\r\n'
399401
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
400402

401403
_PYCACHE = '__pycache__'

Lib/opcode.py

+1-6
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,6 @@ def jabs_op(name, op):
5555
# Blank lines correspond to available opcodes
5656

5757
def_op('POP_TOP', 1)
58-
def_op('ROT_TWO', 2)
59-
def_op('ROT_THREE', 3)
60-
def_op('DUP_TOP', 4)
61-
def_op('DUP_TOP_TWO', 5)
62-
def_op('ROT_FOUR', 6)
6358

6459
def_op('NOP', 9)
6560
def_op('UNARY_POSITIVE', 10)
@@ -116,7 +111,7 @@ def jabs_op(name, op):
116111
name_op('DELETE_ATTR', 96) # ""
117112
name_op('STORE_GLOBAL', 97) # ""
118113
name_op('DELETE_GLOBAL', 98) # ""
119-
def_op('ROT_N', 99)
114+
def_op('SWAP', 99)
120115
def_op('LOAD_CONST', 100) # Index in const list
121116
hasconst.append(100)
122117
name_op('LOAD_NAME', 101) # Index in name list

Lib/test/test__opcode.py

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ class OpcodeTests(unittest.TestCase):
1111

1212
def test_stack_effect(self):
1313
self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1)
14-
self.assertEqual(stack_effect(dis.opmap['DUP_TOP_TWO']), 2)
1514
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1)
1615
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1)
1716
self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2)

Lib/test/test_dis.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1195,8 +1195,8 @@ def _prepare_test_cases():
11951195
Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None),
11961196
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=158, starts_line=None, is_jump_target=False, positions=None),
11971197
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=160, starts_line=25, is_jump_target=False, positions=None),
1198-
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
1199-
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None),
1198+
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=162, starts_line=None, is_jump_target=False, positions=None),
1199+
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=164, starts_line=None, is_jump_target=False, positions=None),
12001200
Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None),
12011201
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None),
12021202
Instruction(opname='JUMP_FORWARD', opcode=110, arg=25, argval=222, argrepr='to 222', offset=170, starts_line=None, is_jump_target=False, positions=None),

Lib/test/test_peepholer.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,8 +119,8 @@ def f():
119119
def test_pack_unpack(self):
120120
for line, elem in (
121121
('a, = a,', 'LOAD_CONST',),
122-
('a, b = a, b', 'ROT_TWO',),
123-
('a, b, c = a, b, c', 'ROT_THREE',),
122+
('a, b = a, b', 'SWAP',),
123+
('a, b, c = a, b, c', 'SWAP',),
124124
):
125125
with self.subTest(line=line):
126126
code = compile(line,'','single')
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Replace several stack manipulation instructions (``DUP_TOP``,
2+
``DUP_TOP_TWO``, ``ROT_TWO``, ``ROT_THREE``, ``ROT_FOUR``, and ``ROT_N``)
3+
with new :opcode:`COPY` and :opcode:`SWAP` instructions.

0 commit comments

Comments
 (0)