bpo-46329: Streamline calling sequence a bit. (GH-31465)

* Move handling of bound-methods to PRECALL.

* Remove call_shape.postcall_shrink

* Remove call_shape.callable

* Remove call_shape.callable. Change CALL oparg to match PRECALL oparg.

* Move KW_NAMES before PRECALL.

* Update opcode docs in dis.rst
This commit is contained in:
Mark Shannon 2022-02-21 18:26:47 +00:00 committed by GitHub
parent 0a222db2bc
commit 59585d6b2e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 218 additions and 178 deletions

View file

@ -36,11 +36,12 @@ the following command can be used to display the disassembly of
>>> dis.dis(myfunc)
1 0 RESUME 0
2 2 LOAD_GLOBAL 0 (len)
4 LOAD_FAST 0 (alist)
6 PRECALL_FUNCTION 1
8 CALL 0
10 RETURN_VALUE
2 2 PUSH_NULL
4 LOAD_GLOBAL 0 (len)
6 LOAD_FAST 0 (alist)
8 PRECALL 1
10 CALL 1
12 RETURN_VALUE
(The "2" is a line number).
@ -106,9 +107,10 @@ Example::
... print(instr.opname)
...
RESUME
PUSH_NULL
LOAD_GLOBAL
LOAD_FAST
PRECALL_FUNCTION
PRECALL
CALL
RETURN_VALUE
@ -1063,18 +1065,28 @@ iterations of the loop.
with ``__cause__`` set to ``TOS``)
.. opcode:: CALL (named)
.. opcode:: CALL (argc)
Calls a callable object with the number of positional arguments specified by
the preceding :opcode:`PRECALL_FUNCTION` or :opcode:`PRECALL_METHOD` and
the named arguments specified by the preceding :opcode:`KW_NAMES`, if any.
*named* indicates the number of named arguments.
On the stack are (in ascending order):
Calls a callable object with the number of arguments specified by ``argc``,
including the named arguments specified by the preceding
:opcode:`KW_NAMES`, if any.
On the stack are (in ascending order), either:
* NULL
* The callable
* The positional arguments
* The named arguments
or:
* The callable
* ``self``
* The remaining positional arguments
* The named arguments
``argc`` is the total of the positional and named arguments, excluding
``self`` when a ``NULL`` is not present.
``CALL`` pops all arguments and the callable object off the stack,
calls the callable object with those arguments, and pushes the return value
returned by the callable object.
@ -1102,33 +1114,34 @@ iterations of the loop.
Loads a method named ``co_names[namei]`` from the TOS object. TOS is popped.
This bytecode distinguishes two cases: if TOS has a method with the correct
name, the bytecode pushes the unbound method and TOS. TOS will be used as
the first argument (``self``) by :opcode:`PRECALL_METHOD` when calling the
the first argument (``self``) by :opcode:`CALL` when calling the
unbound method. Otherwise, ``NULL`` and the object return by the attribute
lookup are pushed.
.. versionadded:: 3.7
.. opcode:: PRECALL_METHOD (argc)
.. opcode:: PRECALL (argc)
Prefixes :opcode:`CALL` (possibly with an intervening ``KW_NAMES``).
This opcode is designed to be used with :opcode:`LOAD_METHOD`.
Sets internal variables, so that :opcode:`CALL`
clean up after :opcode:`LOAD_METHOD` correctly.
Prefixes :opcode:`CALL`. Logically this is a no op.
It exists to enable effective specialization of calls.
``argc`` is the number of arguments as described in :opcode:`CALL`.
.. versionadded:: 3.11
.. opcode:: PRECALL_FUNCTION (args)
.. opcode:: PUSH_NULL
Prefixes :opcode:`CALL` (possibly with an intervening ``KW_NAMES``).
Sets internal variables, so that :opcode:`CALL` can execute correctly.
Pushes a ``NULL`` to the stack.
Used in the call sequence to match the ``NULL`` pushed by
:opcode:`LOAD_METHOD` for non-method calls.
.. versionadded:: 3.11
.. opcode:: KW_NAMES (i)
Prefixes :opcode:`PRECALL`.
Stores a reference to ``co_consts[consti]`` into an internal variable
for use by :opcode:`CALL`. ``co_consts[consti]`` must be a tuple of strings.

View file

@ -386,6 +386,7 @@ def _write_atomic(path, data, mode=0o666):
# ROT_TWO/ROT_THREE/ROT_FOUR/ROT_N with SWAP)
# Python 3.11a5 3478 (New CALL opcodes)
# Python 3.11a5 3479 (Add PUSH_NULL opcode)
# Python 3.11a5 3480 (New CALL opcodes, second iteration)
# Python 3.12 will start with magic number 3500
@ -403,7 +404,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 = (3479).to_bytes(2, 'little') + b'\r\n'
MAGIC_NUMBER = (3480).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__'

View file

@ -109,7 +109,7 @@ def _f(a):
LOAD_GLOBAL 0 (print)
LOAD_FAST 0 (a)
PRECALL 1
CALL 0
CALL 1
POP_TOP
%3d LOAD_CONST 1 (1)
@ -125,7 +125,7 @@ def _f(a):
LOAD_GLOBAL 0
LOAD_FAST 0
PRECALL 1
CALL 0
CALL 1
POP_TOP
LOAD_CONST 1
RETURN_VALUE
@ -147,7 +147,7 @@ def bug708901():
%3d LOAD_CONST 2 (10)
%3d PRECALL 2
CALL 0
CALL 2
GET_ITER
>> FOR_ITER 2 (to 22)
STORE_FAST 0 (res)
@ -319,7 +319,7 @@ def bug42562():
LOAD_NAME 3 (fun)
LOAD_CONST 0 (1)
PRECALL 1
CALL 0
CALL 1
LOAD_NAME 2 (__annotations__)
LOAD_CONST 2 ('y')
STORE_SUBSCR
@ -330,7 +330,7 @@ def bug42562():
LOAD_NAME 3 (fun)
LOAD_CONST 3 (0)
PRECALL 1
CALL 0
CALL 1
STORE_SUBSCR
LOAD_NAME 1 (int)
POP_TOP
@ -1164,7 +1164,7 @@ def _prepare_test_cases():
Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Hello world!', argrepr="'Hello world!'", offset=36, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=7, argval=7, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=44, starts_line=8, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None),
@ -1191,7 +1191,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=34, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=36, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=4, argval=4, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=44, starts_line=6, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None),
@ -1209,7 +1209,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=16, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=6, argval=6, argrepr='', offset=20, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=24, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=26, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None),
@ -1221,7 +1221,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=4, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=6, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=8, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=10, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=10, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=12, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='FOR_ITER', opcode=93, arg=19, argval=54, argrepr='to 54', offset=14, starts_line=None, is_jump_target=True, positions=None),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False, positions=None),
@ -1229,7 +1229,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=20, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=24, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=30, starts_line=5, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=32, starts_line=None, is_jump_target=False, positions=None),
@ -1247,7 +1247,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=56, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=58, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=66, starts_line=11, is_jump_target=True, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=57, argval=114, argrepr='to 114', offset=68, starts_line=None, is_jump_target=False, positions=None),
@ -1255,7 +1255,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=72, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=76, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=78, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=78, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=80, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=82, starts_line=13, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=84, starts_line=None, is_jump_target=False, positions=None),
@ -1277,7 +1277,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=116, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=118, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=120, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=124, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=126, starts_line=20, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=128, starts_line=21, is_jump_target=False, positions=None),
@ -1291,13 +1291,13 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=144, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=146, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=148, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=152, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=154, starts_line=25, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=156, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=158, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=2, argval=2, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=190, argrepr='to 190', offset=166, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None),
@ -1320,7 +1320,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=202, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=204, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=206, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=240, argrepr='to 240', offset=214, starts_line=None, is_jump_target=False, positions=None),
@ -1332,7 +1332,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=226, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=228, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=234, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=236, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=238, starts_line=None, is_jump_target=False, positions=None),
@ -1341,7 +1341,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=244, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=246, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=248, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=252, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=254, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=256, starts_line=None, is_jump_target=False, positions=None),
@ -1350,7 +1350,7 @@ def _prepare_test_cases():
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=262, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=264, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=266, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=268, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=268, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=270, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=272, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=274, starts_line=None, is_jump_target=False, positions=None),

View file

@ -0,0 +1,2 @@
Move ``KW_NAMES`` before ``PRECALL`` instruction in call sequence. Change
``operand`` of ``CALL`` to match ``PRECALL`` for easier specialization.

View file

@ -3,11 +3,11 @@ unsigned char M_test_frozenmain[] = {
227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,
0,0,0,0,0,115,104,0,0,0,151,0,100,0,100,1,
108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2,
100,2,166,1,171,0,1,0,2,0,101,2,100,3,101,0,
106,3,166,2,171,0,1,0,2,0,101,1,106,4,166,0,
100,2,166,1,171,1,1,0,2,0,101,2,100,3,101,0,
106,3,166,2,171,2,1,0,2,0,101,1,106,4,166,0,
171,0,100,4,25,0,90,5,100,5,68,0,93,16,90,6,
2,0,101,2,100,6,101,6,155,0,100,7,101,5,101,6,
25,0,155,0,157,4,166,1,171,0,1,0,113,33,100,1,
25,0,155,0,157,4,166,1,171,1,1,0,113,33,100,1,
83,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122,
101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8,
115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103,

View file

@ -1585,15 +1585,19 @@ pop_frame(PyThreadState *tstate, InterpreterFrame *frame)
}
/* It is only between the PRECALL instruction and the following CALL,
* that these values have any meaning.
* that this has any meaning.
*/
typedef struct {
PyObject *callable;
PyObject *kwnames;
int total_args;
int postcall_shrink;
} CallShape;
static inline bool
is_method(PyObject **stack_pointer, int args) {
return PEEK(args+2) != NULL;
}
#define KWNAMES_LEN() \
(call_shape.kwnames == NULL ? 0 : ((int)PyTuple_GET_SIZE(call_shape.kwnames)))
PyObject* _Py_HOT_FUNCTION
_PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag)
@ -1616,11 +1620,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
CFrame cframe;
CallShape call_shape;
call_shape.kwnames = NULL; // Borrowed reference. Reset by CALL instructions.
/* The following three values are always set by the PRECALL instructions.
They are set here to keep the compiler happy. */
call_shape.postcall_shrink = 0;
call_shape.total_args = 0;
call_shape.callable = NULL; // Strong reference
/* WARNING: Because the CFrame lives on the C stack,
* but can be accessed from a heap allocated object (tstate)
@ -4513,23 +4512,31 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
int nargs = oparg + is_method;
/* Move ownership of reference from stack to call_shape
* and make sure that NULL is cleared from stack */
call_shape.callable = PEEK(nargs + 1);
call_shape.postcall_shrink = 2-is_method;
call_shape.total_args = nargs;
assert(call_shape.kwnames == NULL);
PyObject *function = PEEK(nargs + 1);
#ifdef Py_STATS
extern int _PySpecialization_ClassifyCallable(PyObject *);
SpecializationStats *stats =
&_py_stats.opcode_stats[PRECALL].specialization;
stats->failure++;
int kind = _PySpecialization_ClassifyCallable(call_shape.callable);
int kind = _PySpecialization_ClassifyCallable(function);
stats->failure_kinds[kind]++;
#endif
if (!is_method && Py_TYPE(function) == &PyMethod_Type) {
PyObject *meth = ((PyMethodObject *)function)->im_func;
PyObject *self = ((PyMethodObject *)function)->im_self;
Py_INCREF(meth);
Py_INCREF(self);
PEEK(oparg+1) = self;
PEEK(oparg+2) = meth;
Py_DECREF(function);
function = meth;
}
DISPATCH();
}
TARGET(KW_NAMES) {
assert(call_shape.kwnames == NULL);
assert(oparg < PyTuple_GET_SIZE(consts));
call_shape.kwnames = GETITEM(consts, oparg);
DISPATCH();
@ -4537,25 +4544,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL) {
PREDICTED(CALL);
PyObject *function;
assert((oparg == 0 && call_shape.kwnames == NULL)
|| (oparg != 0 && oparg == PyTuple_GET_SIZE(call_shape.kwnames)));
int is_meth;
call_function:
function = call_shape.callable;
if (Py_TYPE(function) == &PyMethod_Type) {
PyObject *meth = ((PyMethodObject *)function)->im_func;
PyObject *self = ((PyMethodObject *)function)->im_self;
Py_INCREF(meth);
Py_INCREF(self);
PEEK(call_shape.total_args + 1) = self;
Py_DECREF(function);
function = meth;
call_shape.total_args++;
assert(call_shape.postcall_shrink >= 1);
call_shape.postcall_shrink--;
}
int total_args = call_shape.total_args;
int positional_args = total_args - oparg;
is_meth = is_method(stack_pointer, oparg);
int total_args = oparg + is_meth;
PyObject *function = PEEK(total_args + 1);
int positional_args = total_args - KWNAMES_LEN();
// Check if the call can be inlined or not
if (Py_TYPE(function) == &PyFunction_Type && tstate->interp->eval_frame == NULL) {
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(function))->co_flags;
@ -4566,7 +4560,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
stack_pointer, positional_args, call_shape.kwnames
);
call_shape.kwnames = NULL;
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
// The frame has stolen all the arguments from the stack,
// so there is no need to clean them up.
if (new_frame == NULL) {
@ -4599,7 +4593,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
for (int i = 0; i < total_args; i++) {
Py_DECREF(stack_pointer[i]);
}
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
PUSH(res);
if (res == NULL) {
goto error;
@ -4610,14 +4604,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_ADAPTIVE) {
SpecializedCacheEntry *cache = GET_CACHE();
int named_args = cache->adaptive.original_oparg;
assert((named_args == 0 && call_shape.kwnames == NULL)
|| (named_args != 0 && named_args == PyTuple_GET_SIZE(call_shape.kwnames)));
int original_oparg = cache->adaptive.original_oparg;
if (cache->adaptive.counter == 0) {
next_instr--;
int nargs = call_shape.total_args;
int is_meth = is_method(stack_pointer, original_oparg);
int nargs = original_oparg + is_meth;
PyObject *callable = PEEK(nargs + 1);
int err = _Py_Specialize_CallNoKw(
call_shape.callable, next_instr, nargs,
callable, next_instr, nargs,
call_shape.kwnames, cache, BUILTINS());
if (err < 0) {
goto error;
@ -4627,7 +4621,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
else {
STAT_INC(CALL, deferred);
cache->adaptive.counter--;
oparg = named_args;
oparg = original_oparg;
goto call_function;
}
}
@ -4635,10 +4629,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_PY_EXACT_ARGS) {
assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE();
int argcount = call_shape.total_args;
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
int original_oparg = caches->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int argcount = original_oparg + is_meth;
PyObject *callable = PEEK(argcount + 1);
DEOPT_IF(!PyFunction_Check(callable), CALL);
_PyCallCache *cache1 = &caches[-1].call;
PyFunctionObject *func = (PyFunctionObject *)call_shape.callable;
PyFunctionObject *func = (PyFunctionObject *)callable;
DEOPT_IF(func->func_version != cache1->func_version, CALL);
PyCodeObject *code = (PyCodeObject *)func->func_code;
DEOPT_IF(code->co_argcount != argcount, CALL);
@ -4654,7 +4651,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
for (int i = argcount; i < code->co_nlocalsplus; i++) {
new_frame->localsplus[i] = NULL;
}
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
_PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = frame;
frame = cframe.current_frame = new_frame;
@ -4664,10 +4661,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_PY_WITH_DEFAULTS) {
assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE();
int argcount = call_shape.total_args;
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
int original_oparg = caches->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int argcount = original_oparg + is_meth;
PyObject *callable = PEEK(argcount + 1);
DEOPT_IF(!PyFunction_Check(callable), CALL);
_PyCallCache *cache1 = &caches[-1].call;
PyFunctionObject *func = (PyFunctionObject *)call_shape.callable;
PyFunctionObject *func = (PyFunctionObject *)callable;
DEOPT_IF(func->func_version != cache1->func_version, CALL);
PyCodeObject *code = (PyCodeObject *)func->func_code;
DEOPT_IF(argcount > code->co_argcount, CALL);
@ -4691,7 +4691,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
for (int i = code->co_argcount; i < code->co_nlocalsplus; i++) {
new_frame->localsplus[i] = NULL;
}
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
_PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = frame;
frame = cframe.current_frame = new_frame;
@ -4701,14 +4701,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW_TYPE_1) {
assert(call_shape.kwnames == NULL);
assert(cframe.use_tracing == 0);
DEOPT_IF(call_shape.total_args != 1, CALL);
assert(GET_CACHE()->adaptive.original_oparg == 1);
DEOPT_IF(is_method(stack_pointer, 1), CALL);
PyObject *obj = TOP();
PyObject *callable = SECOND();
DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL);
PyObject *res = Py_NewRef(Py_TYPE(obj));
Py_DECREF(callable);
Py_DECREF(obj);
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2);
SET_TOP(res);
NOTRACE_DISPATCH();
}
@ -4716,16 +4717,18 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW_STR_1) {
assert(call_shape.kwnames == NULL);
assert(cframe.use_tracing == 0);
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
DEOPT_IF(call_shape.total_args != 1, CALL);
assert(GET_CACHE()->adaptive.original_oparg == 1);
PyObject *callable = PEEK(2);
DEOPT_IF(!PyType_Check(callable), CALL);
PyTypeObject *tp = (PyTypeObject *)callable;
DEOPT_IF(is_method(stack_pointer, 1), CALL);
DEOPT_IF(tp != &PyUnicode_Type, CALL);
STAT_INC(CALL, hit);
PyObject *arg = TOP();
PyObject *res = PyObject_Str(arg);
Py_DECREF(arg);
Py_DECREF(&PyUnicode_Type);
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2);
SET_TOP(res);
if (res == NULL) {
goto error;
@ -4736,16 +4739,19 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW_TUPLE_1) {
assert(call_shape.kwnames == NULL);
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
DEOPT_IF(call_shape.total_args != 1, CALL);
assert(GET_CACHE()->adaptive.original_oparg == 1);
int is_meth = is_method(stack_pointer, 1);
PyObject *callable = PEEK(2);
DEOPT_IF(!PyType_Check(callable), CALL);
PyTypeObject *tp = (PyTypeObject *)callable;
DEOPT_IF(is_meth, CALL);
DEOPT_IF(tp != &PyTuple_Type, CALL);
STAT_INC(CALL, hit);
PyObject *arg = TOP();
PyObject *res = PySequence_Tuple(arg);
Py_DECREF(arg);
Py_DECREF(&PyTuple_Type);
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2);
SET_TOP(res);
if (res == NULL) {
goto error;
@ -4755,22 +4761,25 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
}
TARGET(CALL_BUILTIN_CLASS) {
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
int original_oparg = GET_CACHE()->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
int kwnames_len = KWNAMES_LEN();
PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(!PyType_Check(callable), CALL);
PyTypeObject *tp = (PyTypeObject *)callable;
DEOPT_IF(tp->tp_vectorcall == NULL, CALL);
STAT_INC(CALL, hit);
int kwnames_len = GET_CACHE()->adaptive.original_oparg;
int nargs = call_shape.total_args - kwnames_len;
STACK_SHRINK(call_shape.total_args);
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, nargs, call_shape.kwnames);
STACK_SHRINK(total_args);
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer,
total_args-kwnames_len, call_shape.kwnames);
call_shape.kwnames = NULL;
/* Free the arguments. */
for (int i = 0; i < call_shape.total_args; i++) {
for (int i = 0; i < total_args; i++) {
Py_DECREF(stack_pointer[i]);
}
Py_DECREF(tp);
STACK_SHRINK(call_shape.postcall_shrink-1);
STACK_SHRINK(1-is_meth);
SET_TOP(res);
if (res == NULL) {
goto error;
@ -4783,8 +4792,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(cframe.use_tracing == 0);
/* Builtin METH_O functions */
assert(call_shape.kwnames == NULL);
DEOPT_IF(call_shape.total_args != 1, CALL);
PyObject *callable = call_shape.callable;
SpecializedCacheEntry *caches = GET_CACHE();
int original_oparg = caches->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
DEOPT_IF(total_args != 1, CALL);
PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL);
STAT_INC(CALL, hit);
@ -4802,7 +4815,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
Py_DECREF(arg);
Py_DECREF(callable);
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
SET_TOP(res);
if (res == NULL) {
goto error;
@ -4815,27 +4828,30 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(cframe.use_tracing == 0);
/* Builtin METH_FASTCALL functions, without keywords */
assert(call_shape.kwnames == NULL);
PyObject *callable = call_shape.callable;
SpecializedCacheEntry *caches = GET_CACHE();
int original_oparg = caches->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL,
CALL);
STAT_INC(CALL, hit);
int nargs = call_shape.total_args;
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
STACK_SHRINK(nargs);
STACK_SHRINK(total_args);
/* res = func(self, args, nargs) */
PyObject *res = ((_PyCFunctionFast)(void(*)(void))cfunc)(
PyCFunction_GET_SELF(callable),
stack_pointer,
nargs);
total_args);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
/* Free the arguments. */
for (int i = 0; i < nargs; i++) {
for (int i = 0; i < total_args; i++) {
Py_DECREF(stack_pointer[i]);
}
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
PUSH(res);
Py_DECREF(callable);
if (res == NULL) {
@ -4853,19 +4869,16 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) {
assert(cframe.use_tracing == 0);
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */
PyObject *callable = call_shape.callable;
SpecializedCacheEntry *caches = GET_CACHE();
int original_oparg = caches->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) !=
(METH_FASTCALL | METH_KEYWORDS), CALL);
STAT_INC(CALL, hit);
int kwnames_len = GET_CACHE()->adaptive.original_oparg;
assert(
(call_shape.kwnames == NULL && kwnames_len == 0) ||
(call_shape.kwnames != NULL &&
PyTuple_GET_SIZE(call_shape.kwnames) == kwnames_len)
);
int nargs = call_shape.total_args - kwnames_len;
STACK_SHRINK(call_shape.total_args);
STACK_SHRINK(total_args);
/* res = func(self, args, nargs, kwnames) */
_PyCFunctionFastWithKeywords cfunc =
(_PyCFunctionFastWithKeywords)(void(*)(void))
@ -4873,17 +4886,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PyObject *res = cfunc(
PyCFunction_GET_SELF(callable),
stack_pointer,
nargs,
total_args - KWNAMES_LEN(),
call_shape.kwnames
);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
call_shape.kwnames = NULL;
/* Free the arguments. */
for (int i = 0; i < call_shape.total_args; i++) {
for (int i = 0; i < total_args; i++) {
Py_DECREF(stack_pointer[i]);
}
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
PUSH(res);
Py_DECREF(callable);
if (res == NULL) {
@ -4898,11 +4911,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(call_shape.kwnames == NULL);
/* len(o) */
SpecializedCacheEntry *caches = GET_CACHE();
DEOPT_IF(call_shape.total_args != 1, CALL);
assert(caches[0].adaptive.original_oparg == 0);
int original_oparg = caches->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
DEOPT_IF(total_args != 1, CALL);
_PyObjectCache *cache1 = &caches[-1].obj;
PyObject *callable = call_shape.callable;
PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(callable != cache1->obj, CALL);
STAT_INC(CALL, hit);
@ -4914,7 +4928,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PyObject *res = PyLong_FromSsize_t(len_i);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
SET_TOP(res);
Py_DECREF(callable);
Py_DECREF(arg);
@ -4929,11 +4943,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(call_shape.kwnames == NULL);
/* isinstance(o, o2) */
SpecializedCacheEntry *caches = GET_CACHE();
assert(caches[0].adaptive.original_oparg == 0);
DEOPT_IF(call_shape.total_args != 2, CALL);
int original_oparg = caches->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(total_args != 2, CALL);
_PyObjectCache *cache1 = &caches[-1].obj;
DEOPT_IF(call_shape.callable != cache1->obj, CALL);
DEOPT_IF(callable != cache1->obj, CALL);
STAT_INC(CALL, hit);
PyObject *cls = POP();
@ -4946,11 +4963,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PyObject *res = PyBool_FromLong(retval);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
SET_TOP(res);
Py_DECREF(inst);
Py_DECREF(cls);
Py_DECREF(call_shape.callable);
Py_DECREF(callable);
if (res == NULL) {
goto error;
}
@ -4961,9 +4978,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(cframe.use_tracing == 0);
assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE();
int original_oparg = caches->adaptive.original_oparg;
_PyObjectCache *cache1 = &caches[-1].obj;
DEOPT_IF(call_shape.total_args != 2, CALL);
DEOPT_IF(call_shape.callable != cache1->obj, CALL);
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(total_args != 2, CALL);
DEOPT_IF(callable != cache1->obj, CALL);
PyObject *list = SECOND();
DEOPT_IF(!PyList_Check(list), CALL);
STAT_INC(CALL, hit);
@ -4974,18 +4995,22 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
}
Py_DECREF(arg);
Py_DECREF(list);
STACK_SHRINK(call_shape.postcall_shrink+1);
STACK_SHRINK(3-is_meth);
Py_INCREF(Py_None);
SET_TOP(Py_None);
Py_DECREF(call_shape.callable);
Py_DECREF(callable);
NOTRACE_DISPATCH();
}
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) {
assert(call_shape.kwnames == NULL);
DEOPT_IF(call_shape.total_args != 2, CALL);
DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL);
PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method;
int original_oparg = GET_CACHE()->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(total_args != 2, CALL);
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
DEOPT_IF(meth->ml_flags != METH_O, CALL);
STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth;
@ -5001,9 +5026,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
Py_DECREF(self);
Py_DECREF(arg);
STACK_SHRINK(call_shape.postcall_shrink+1);
STACK_SHRINK(3-is_meth);
SET_TOP(res);
Py_DECREF(call_shape.callable);
Py_DECREF(callable);
if (res == NULL) {
goto error;
}
@ -5013,9 +5038,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) {
assert(call_shape.kwnames == NULL);
DEOPT_IF(call_shape.total_args != 1, CALL);
DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL);
PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method;
int original_oparg = GET_CACHE()->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1);
DEOPT_IF(total_args != 1, CALL);
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL);
STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth;
@ -5029,9 +5058,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
_Py_LeaveRecursiveCall(tstate);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
Py_DECREF(self);
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
SET_TOP(res);
Py_DECREF(call_shape.callable);
Py_DECREF(callable);
if (res == NULL) {
goto error;
}
@ -5041,13 +5070,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) {
assert(call_shape.kwnames == NULL);
int original_oparg = GET_CACHE()->adaptive.original_oparg;
int is_meth = is_method(stack_pointer, original_oparg);
int total_args = original_oparg + is_meth;
PyObject *callable = PEEK(total_args + 1);
/* Builtin METH_FASTCALL methods, without keywords */
DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL);
PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method;
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL);
STAT_INC(CALL, hit);
_PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth;
int nargs = call_shape.total_args-1;
int nargs = total_args-1;
STACK_SHRINK(nargs);
PyObject *self = TOP();
PyObject *res = cfunc(self, stack_pointer, nargs);
@ -5057,9 +5090,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
Py_DECREF(stack_pointer[i]);
}
Py_DECREF(self);
STACK_SHRINK(call_shape.postcall_shrink);
STACK_SHRINK(2-is_meth);
SET_TOP(res);
Py_DECREF(call_shape.callable);
Py_DECREF(callable);
if (res == NULL) {
goto error;
}

View file

@ -1800,7 +1800,7 @@ compiler_call_exit_with_nones(struct compiler *c) {
ADDOP_LOAD_CONST(c, Py_None);
ADDOP_LOAD_CONST(c, Py_None);
ADDOP_I(c, PRECALL, 2);
ADDOP_I(c, CALL, 0);
ADDOP_I(c, CALL, 2);
return 1;
}
@ -4679,16 +4679,12 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
if (kwdsl) {
VISIT_SEQ(c, keyword, kwds);
ADDOP_I(c, PRECALL, argsl + kwdsl);
if (!compiler_call_simple_kw_helper(c, kwds, kwdsl)) {
return 0;
};
ADDOP_I(c, CALL, kwdsl);
}
else {
ADDOP_I(c, PRECALL, argsl);
ADDOP_I(c, CALL, 0);
}
ADDOP_I(c, PRECALL, argsl + kwdsl);
ADDOP_I(c, CALL, argsl + kwdsl);
c->u->u_lineno = old_lineno;
return 1;
}
@ -4758,7 +4754,7 @@ compiler_joined_str(struct compiler *c, expr_ty e)
ADDOP_I(c, LIST_APPEND, 1);
}
ADDOP_I(c, PRECALL, 1);
ADDOP_I(c, CALL, 0);
ADDOP_I(c, CALL, 1);
}
else {
VISIT_SEQ(c, expr, e->v.JoinedStr.values);
@ -4927,18 +4923,13 @@ compiler_call_helper(struct compiler *c,
}
if (nkwelts) {
VISIT_SEQ(c, keyword, keywords);
ADDOP_I(c, PRECALL, n + nelts + nkwelts);
if (!compiler_call_simple_kw_helper(c, keywords, nkwelts)) {
return 0;
};
ADDOP_I(c, CALL, nkwelts);
return 1;
}
else {
ADDOP_I(c, PRECALL, n + nelts);
ADDOP_I(c, CALL, 0);
return 1;
}
ADDOP_I(c, PRECALL, n + nelts + nkwelts);
ADDOP_I(c, CALL, n + nelts + nkwelts);
return 1;
ex_call: