Skip to content

gh-101632: Add a RETURN_CONST instruction #101633

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Feb 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,13 @@ iterations of the loop.
Returns with ``STACK[-1]`` to the caller of the function.


.. opcode:: RETURN_CONST (consti)

Returns with ``co_consts[consti]`` to the caller of the function.

.. versionadded:: 3.12


.. opcode:: YIELD_VALUE

Yields ``STACK.pop()`` from a :term:`generator`.
Expand Down
10 changes: 5 additions & 5 deletions Include/internal/pycore_opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 9 additions & 7 deletions Include/opcode.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Lib/dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
MAKE_FUNCTION_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure')

LOAD_CONST = opmap['LOAD_CONST']
RETURN_CONST = opmap['RETURN_CONST']
LOAD_GLOBAL = opmap['LOAD_GLOBAL']
BINARY_OP = opmap['BINARY_OP']
JUMP_BACKWARD = opmap['JUMP_BACKWARD']
Expand Down Expand Up @@ -363,7 +364,7 @@ def _get_const_value(op, arg, co_consts):
assert op in hasconst

argval = UNKNOWN
if op == LOAD_CONST:
if op == LOAD_CONST or op == RETURN_CONST:
if co_consts is not None:
argval = co_consts[arg]
return argval
Expand Down
3 changes: 2 additions & 1 deletion Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.12a5 3515 (Embed jump mask in COMPARE_OP oparg)
# Python 3.12a5 3516 (Add COMPARE_AND_BRANCH instruction)
# Python 3.12a5 3517 (Change YIELD_VALUE oparg to exception block depth)
# Python 3.12a5 3518 (Add RETURN_CONST instruction)

# Python 3.13 will start with 3550

Expand All @@ -443,7 +444,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 = (3517).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3518).to_bytes(2, 'little') + b'\r\n'

_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c

Expand Down
2 changes: 2 additions & 0 deletions Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ def pseudo_op(name, op, real_ops):
def_op('CONTAINS_OP', 118)
def_op('RERAISE', 119)
def_op('COPY', 120)
def_op('RETURN_CONST', 121)
hasconst.append(121)
def_op('BINARY_OP', 122)
jrel_op('SEND', 123) # Number of bytes to skip
def_op('LOAD_FAST', 124) # Local variable number, no null check
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_ast.py
Original file line number Diff line number Diff line change
Expand Up @@ -1900,7 +1900,7 @@ def get_load_const(self, tree):
co = compile(tree, '<string>', 'exec')
consts = []
for instr in dis.get_instructions(co):
if instr.opname == 'LOAD_CONST':
if instr.opname == 'LOAD_CONST' or instr.opname == 'RETURN_CONST':
consts.append(instr.argval)
return consts

Expand Down
1 change: 1 addition & 0 deletions Lib/test/test_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ def f():
pass
PY_CODE_LOCATION_INFO_NO_COLUMNS = 13
f.__code__ = f.__code__.replace(
co_stacksize=1,
co_firstlineno=42,
co_code=bytes(
[
Expand Down
18 changes: 8 additions & 10 deletions Lib/test/test_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,7 +741,7 @@ def unused_code_at_end():
# RETURN_VALUE opcode. This does not always crash an interpreter.
# When you build with the clang memory sanitizer it reliably aborts.
self.assertEqual(
'RETURN_VALUE',
'RETURN_CONST',
list(dis.get_instructions(unused_code_at_end))[-1].opname)

def test_dont_merge_constants(self):
Expand Down Expand Up @@ -822,10 +822,9 @@ def unused_block_while_else():

for func in funcs:
opcodes = list(dis.get_instructions(func))
self.assertLessEqual(len(opcodes), 4)
self.assertEqual('LOAD_CONST', opcodes[-2].opname)
self.assertEqual(None, opcodes[-2].argval)
self.assertEqual('RETURN_VALUE', opcodes[-1].opname)
self.assertLessEqual(len(opcodes), 3)
self.assertEqual('RETURN_CONST', opcodes[-1].opname)
self.assertEqual(None, opcodes[-1].argval)

def test_false_while_loop(self):
def break_in_while():
Expand All @@ -841,10 +840,9 @@ def continue_in_while():
# Check that we did not raise but we also don't generate bytecode
for func in funcs:
opcodes = list(dis.get_instructions(func))
self.assertEqual(3, len(opcodes))
self.assertEqual('LOAD_CONST', opcodes[1].opname)
self.assertEqual(2, len(opcodes))
self.assertEqual('RETURN_CONST', opcodes[1].opname)
self.assertEqual(None, opcodes[1].argval)
self.assertEqual('RETURN_VALUE', opcodes[2].opname)

def test_consts_in_conditionals(self):
def and_true(x):
Expand Down Expand Up @@ -1311,7 +1309,7 @@ def test_multiline_generator_expression(self):
line=1, end_line=2, column=1, end_column=8, occurrence=1)
self.assertOpcodeSourcePositionIs(compiled_code, 'JUMP_BACKWARD',
line=1, end_line=2, column=1, end_column=8, occurrence=1)
self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE',
self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
line=1, end_line=6, column=0, end_column=32, occurrence=1)

def test_multiline_async_generator_expression(self):
Expand All @@ -1328,7 +1326,7 @@ def test_multiline_async_generator_expression(self):
self.assertIsInstance(compiled_code, types.CodeType)
self.assertOpcodeSourcePositionIs(compiled_code, 'YIELD_VALUE',
line=1, end_line=2, column=1, end_column=8, occurrence=2)
self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_VALUE',
self.assertOpcodeSourcePositionIs(compiled_code, 'RETURN_CONST',
line=1, end_line=6, column=0, end_column=32, occurrence=1)

def test_multiline_list_comprehension(self):
Expand Down
Loading