Skip to content

Commit

Permalink
pythonGH-77273: Better bytecodes for f-strings (pythonGH-6132)
Browse files Browse the repository at this point in the history
  • Loading branch information
markshannon authored Jun 14, 2023
1 parent 307bcea commit 1d857da
Show file tree
Hide file tree
Showing 15 changed files with 519 additions and 479 deletions.
53 changes: 37 additions & 16 deletions Doc/library/dis.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1465,26 +1465,47 @@ iterations of the loop.
an argument from two-byte to four-byte.


.. opcode:: FORMAT_VALUE (flags)
.. opcode:: CONVERT_VALUE (oparg)

Used for implementing formatted literal strings (f-strings). Pops
an optional *fmt_spec* from the stack, then a required *value*.
*flags* is interpreted as follows:
Convert value to a string, depending on ``oparg``::

* ``(flags & 0x03) == 0x00``: *value* is formatted as-is.
* ``(flags & 0x03) == 0x01``: call :func:`str` on *value* before
formatting it.
* ``(flags & 0x03) == 0x02``: call :func:`repr` on *value* before
formatting it.
* ``(flags & 0x03) == 0x03``: call :func:`ascii` on *value* before
formatting it.
* ``(flags & 0x04) == 0x04``: pop *fmt_spec* from the stack and use
it, else use an empty *fmt_spec*.
value = STACK.pop()
result = func(value)
STACK.push(result)

Formatting is performed using :c:func:`PyObject_Format`. The
result is pushed on the stack.
* ``oparg == 1``: call :func:`str` on *value*
* ``oparg == 2``: call :func:`repr` on *value*
* ``oparg == 3``: call :func:`ascii` on *value*

.. versionadded:: 3.6
Used for implementing formatted literal strings (f-strings).

.. versionadded:: 3.13


.. opcode:: FORMAT_SIMPLE

Formats the value on top of stack::

value = STACK.pop()
result = value.__format__("")
STACK.push(result)

Used for implementing formatted literal strings (f-strings).

.. versionadded:: 3.13

.. opcode:: FORMAT_SPEC

Formats the given value with the given format spec::

spec = STACK.pop()
value = STACK.pop()
result = value.__format__(spec)
STACK.push(result)

Used for implementing formatted literal strings (f-strings).

.. versionadded:: 3.13


.. opcode:: MATCH_CLASS (count)
Expand Down
50 changes: 25 additions & 25 deletions Include/internal/pycore_opcode.h

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

86 changes: 44 additions & 42 deletions Include/opcode.h

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

19 changes: 5 additions & 14 deletions Lib/dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,8 @@
_have_code = (types.MethodType, types.FunctionType, types.CodeType,
classmethod, staticmethod, type)

FORMAT_VALUE = opmap['FORMAT_VALUE']
FORMAT_VALUE_CONVERTERS = (
(None, ''),
(str, 'str'),
(repr, 'repr'),
(ascii, 'ascii'),
)
CONVERT_VALUE = opmap['CONVERT_VALUE']

SET_FUNCTION_ATTRIBUTE = opmap['SET_FUNCTION_ATTRIBUTE']
FUNCTION_ATTR_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure')

Expand Down Expand Up @@ -579,13 +574,9 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
elif deop in hascompare:
argval = cmp_op[arg>>4]
argrepr = argval
elif deop == FORMAT_VALUE:
argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3]
argval = (argval, bool(arg & 0x4))
if argval[1]:
if argrepr:
argrepr += ', '
argrepr += 'with format'
elif deop == CONVERT_VALUE:
argval = (None, str, repr, ascii)[arg]
argrepr = ('', 'str', 'repr', 'ascii')[arg]
elif deop == SET_FUNCTION_ATTRIBUTE:
argrepr = ', '.join(s for i, s in enumerate(FUNCTION_ATTR_FLAGS)
if arg & (1<<i))
Expand Down
6 changes: 4 additions & 2 deletions Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,9 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.12b1 3531 (Add PEP 695 changes)
# Python 3.13a1 3550 (Plugin optimizer support)
# Python 3.13a1 3551 (Compact superinstructions)
# Python 3.13a1 3552 (Add SET_FUNCTION_ATTRIBUTE)
# Python 3.13a1 3552 (Remove LOAD_FAST__LOAD_CONST and LOAD_CONST__LOAD_FAST)
# Python 3.13a1 3553 (Add SET_FUNCTION_ATTRIBUTE)
# Python 3.13a1 3554 (more efficient bytecodes for f-strings)

# Python 3.14 will start with 3600

Expand All @@ -464,7 +466,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 = (3552).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3554).to_bytes(2, 'little') + b'\r\n'

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

Expand Down
5 changes: 4 additions & 1 deletion Lib/opcode.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ def pseudo_op(name, op, real_ops):
def_op('CHECK_EXC_MATCH', 36)
def_op('CHECK_EG_MATCH', 37)

def_op('FORMAT_SIMPLE', 40)
def_op('FORMAT_WITH_SPEC', 41)

def_op('WITH_EXCEPT_START', 49)
def_op('GET_AITER', 50)
def_op('GET_ANEXT', 51)
Expand Down Expand Up @@ -213,9 +216,9 @@ def pseudo_op(name, op, real_ops):
def_op('RESUME', 151) # This must be kept in sync with deepfreeze.py
def_op('MATCH_CLASS', 152)

def_op('FORMAT_VALUE', 155)
def_op('BUILD_CONST_KEY_MAP', 156)
def_op('BUILD_STRING', 157)
def_op('CONVERT_VALUE', 158)

def_op('LIST_EXTEND', 162)
def_op('SET_UPDATE', 163)
Expand Down
Loading

0 comments on commit 1d857da

Please sign in to comment.