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) >>> dis.dis(myfunc)
1 0 RESUME 0 1 0 RESUME 0
2 2 LOAD_GLOBAL 0 (len) 2 2 PUSH_NULL
4 LOAD_FAST 0 (alist) 4 LOAD_GLOBAL 0 (len)
6 PRECALL_FUNCTION 1 6 LOAD_FAST 0 (alist)
8 CALL 0 8 PRECALL 1
10 RETURN_VALUE 10 CALL 1
12 RETURN_VALUE
(The "2" is a line number). (The "2" is a line number).
@ -106,9 +107,10 @@ Example::
... print(instr.opname) ... print(instr.opname)
... ...
RESUME RESUME
PUSH_NULL
LOAD_GLOBAL LOAD_GLOBAL
LOAD_FAST LOAD_FAST
PRECALL_FUNCTION PRECALL
CALL CALL
RETURN_VALUE RETURN_VALUE
@ -1063,18 +1065,28 @@ iterations of the loop.
with ``__cause__`` set to ``TOS``) with ``__cause__`` set to ``TOS``)
.. opcode:: CALL (named) .. opcode:: CALL (argc)
Calls a callable object with the number of positional arguments specified by Calls a callable object with the number of arguments specified by ``argc``,
the preceding :opcode:`PRECALL_FUNCTION` or :opcode:`PRECALL_METHOD` and including the named arguments specified by the preceding
the named arguments specified by the preceding :opcode:`KW_NAMES`, if any. :opcode:`KW_NAMES`, if any.
*named* indicates the number of named arguments. On the stack are (in ascending order), either:
On the stack are (in ascending order):
* NULL
* The callable * The callable
* The positional arguments * The positional arguments
* The named 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, ``CALL`` pops all arguments and the callable object off the stack,
calls the callable object with those arguments, and pushes the return value calls the callable object with those arguments, and pushes the return value
returned by the callable object. 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. 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 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 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 unbound method. Otherwise, ``NULL`` and the object return by the attribute
lookup are pushed. lookup are pushed.
.. versionadded:: 3.7 .. versionadded:: 3.7
.. opcode:: PRECALL_METHOD (argc) .. opcode:: PRECALL (argc)
Prefixes :opcode:`CALL` (possibly with an intervening ``KW_NAMES``). Prefixes :opcode:`CALL`. Logically this is a no op.
This opcode is designed to be used with :opcode:`LOAD_METHOD`. It exists to enable effective specialization of calls.
Sets internal variables, so that :opcode:`CALL` ``argc`` is the number of arguments as described in :opcode:`CALL`.
clean up after :opcode:`LOAD_METHOD` correctly.
.. versionadded:: 3.11 .. versionadded:: 3.11
.. opcode:: PRECALL_FUNCTION (args) .. opcode:: PUSH_NULL
Prefixes :opcode:`CALL` (possibly with an intervening ``KW_NAMES``). Pushes a ``NULL`` to the stack.
Sets internal variables, so that :opcode:`CALL` can execute correctly. Used in the call sequence to match the ``NULL`` pushed by
:opcode:`LOAD_METHOD` for non-method calls.
.. versionadded:: 3.11 .. versionadded:: 3.11
.. opcode:: KW_NAMES (i) .. opcode:: KW_NAMES (i)
Prefixes :opcode:`PRECALL`.
Stores a reference to ``co_consts[consti]`` into an internal variable 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. 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) # ROT_TWO/ROT_THREE/ROT_FOUR/ROT_N with SWAP)
# Python 3.11a5 3478 (New CALL opcodes) # Python 3.11a5 3478 (New CALL opcodes)
# Python 3.11a5 3479 (Add PUSH_NULL opcode) # 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 # 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 # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # 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 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'

View file

@ -109,7 +109,7 @@ def _f(a):
LOAD_GLOBAL 0 (print) LOAD_GLOBAL 0 (print)
LOAD_FAST 0 (a) LOAD_FAST 0 (a)
PRECALL 1 PRECALL 1
CALL 0 CALL 1
POP_TOP POP_TOP
%3d LOAD_CONST 1 (1) %3d LOAD_CONST 1 (1)
@ -125,7 +125,7 @@ def _f(a):
LOAD_GLOBAL 0 LOAD_GLOBAL 0
LOAD_FAST 0 LOAD_FAST 0
PRECALL 1 PRECALL 1
CALL 0 CALL 1
POP_TOP POP_TOP
LOAD_CONST 1 LOAD_CONST 1
RETURN_VALUE RETURN_VALUE
@ -147,7 +147,7 @@ def bug708901():
%3d LOAD_CONST 2 (10) %3d LOAD_CONST 2 (10)
%3d PRECALL 2 %3d PRECALL 2
CALL 0 CALL 2
GET_ITER GET_ITER
>> FOR_ITER 2 (to 22) >> FOR_ITER 2 (to 22)
STORE_FAST 0 (res) STORE_FAST 0 (res)
@ -319,7 +319,7 @@ def bug42562():
LOAD_NAME 3 (fun) LOAD_NAME 3 (fun)
LOAD_CONST 0 (1) LOAD_CONST 0 (1)
PRECALL 1 PRECALL 1
CALL 0 CALL 1
LOAD_NAME 2 (__annotations__) LOAD_NAME 2 (__annotations__)
LOAD_CONST 2 ('y') LOAD_CONST 2 ('y')
STORE_SUBSCR STORE_SUBSCR
@ -330,7 +330,7 @@ def bug42562():
LOAD_NAME 3 (fun) LOAD_NAME 3 (fun)
LOAD_CONST 3 (0) LOAD_CONST 3 (0)
PRECALL 1 PRECALL 1
CALL 0 CALL 1
STORE_SUBSCR STORE_SUBSCR
LOAD_NAME 1 (int) LOAD_NAME 1 (int)
POP_TOP 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='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='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='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='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='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), 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=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='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='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='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='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), 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=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='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='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='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='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), 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_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='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='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='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='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), 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_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='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='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='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_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), 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_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='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='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='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='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), 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_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='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='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='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_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), 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_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='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='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='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='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), 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_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='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='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='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=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=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='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='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='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='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), 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_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='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='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_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='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), 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_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='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='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='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='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), 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_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='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='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='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='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), 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_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='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='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='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='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), 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, 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, 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, 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, 100,2,166,1,171,1,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, 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, 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, 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, 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, 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, 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, /* It is only between the PRECALL instruction and the following CALL,
* that these values have any meaning. * that this has any meaning.
*/ */
typedef struct { typedef struct {
PyObject *callable;
PyObject *kwnames; PyObject *kwnames;
int total_args;
int postcall_shrink;
} CallShape; } 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 PyObject* _Py_HOT_FUNCTION
_PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag) _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag)
@ -1616,11 +1620,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
CFrame cframe; CFrame cframe;
CallShape call_shape; CallShape call_shape;
call_shape.kwnames = NULL; // Borrowed reference. Reset by CALL instructions. 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, /* WARNING: Because the CFrame lives on the C stack,
* but can be accessed from a heap allocated object (tstate) * 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; int nargs = oparg + is_method;
/* Move ownership of reference from stack to call_shape /* Move ownership of reference from stack to call_shape
* and make sure that NULL is cleared from stack */ * and make sure that NULL is cleared from stack */
call_shape.callable = PEEK(nargs + 1); PyObject *function = PEEK(nargs + 1);
call_shape.postcall_shrink = 2-is_method;
call_shape.total_args = nargs;
assert(call_shape.kwnames == NULL);
#ifdef Py_STATS #ifdef Py_STATS
extern int _PySpecialization_ClassifyCallable(PyObject *); extern int _PySpecialization_ClassifyCallable(PyObject *);
SpecializationStats *stats = SpecializationStats *stats =
&_py_stats.opcode_stats[PRECALL].specialization; &_py_stats.opcode_stats[PRECALL].specialization;
stats->failure++; stats->failure++;
int kind = _PySpecialization_ClassifyCallable(call_shape.callable); int kind = _PySpecialization_ClassifyCallable(function);
stats->failure_kinds[kind]++; stats->failure_kinds[kind]++;
#endif #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(); DISPATCH();
} }
TARGET(KW_NAMES) { TARGET(KW_NAMES) {
assert(call_shape.kwnames == NULL);
assert(oparg < PyTuple_GET_SIZE(consts)); assert(oparg < PyTuple_GET_SIZE(consts));
call_shape.kwnames = GETITEM(consts, oparg); call_shape.kwnames = GETITEM(consts, oparg);
DISPATCH(); DISPATCH();
@ -4537,25 +4544,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL) { TARGET(CALL) {
PREDICTED(CALL); PREDICTED(CALL);
PyObject *function; int is_meth;
assert((oparg == 0 && call_shape.kwnames == NULL)
|| (oparg != 0 && oparg == PyTuple_GET_SIZE(call_shape.kwnames)));
call_function: call_function:
function = call_shape.callable; is_meth = is_method(stack_pointer, oparg);
if (Py_TYPE(function) == &PyMethod_Type) { int total_args = oparg + is_meth;
PyObject *meth = ((PyMethodObject *)function)->im_func; PyObject *function = PEEK(total_args + 1);
PyObject *self = ((PyMethodObject *)function)->im_self; int positional_args = total_args - KWNAMES_LEN();
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;
// Check if the call can be inlined or not // Check if the call can be inlined or not
if (Py_TYPE(function) == &PyFunction_Type && tstate->interp->eval_frame == NULL) { if (Py_TYPE(function) == &PyFunction_Type && tstate->interp->eval_frame == NULL) {
int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(function))->co_flags; 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 stack_pointer, positional_args, call_shape.kwnames
); );
call_shape.kwnames = NULL; 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, // The frame has stolen all the arguments from the stack,
// so there is no need to clean them up. // so there is no need to clean them up.
if (new_frame == NULL) { if (new_frame == NULL) {
@ -4599,7 +4593,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
for (int i = 0; i < total_args; i++) { for (int i = 0; i < total_args; i++) {
Py_DECREF(stack_pointer[i]); Py_DECREF(stack_pointer[i]);
} }
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
PUSH(res); PUSH(res);
if (res == NULL) { if (res == NULL) {
goto error; goto error;
@ -4610,14 +4604,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_ADAPTIVE) { TARGET(CALL_ADAPTIVE) {
SpecializedCacheEntry *cache = GET_CACHE(); SpecializedCacheEntry *cache = GET_CACHE();
int named_args = cache->adaptive.original_oparg; int original_oparg = cache->adaptive.original_oparg;
assert((named_args == 0 && call_shape.kwnames == NULL)
|| (named_args != 0 && named_args == PyTuple_GET_SIZE(call_shape.kwnames)));
if (cache->adaptive.counter == 0) { if (cache->adaptive.counter == 0) {
next_instr--; 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( int err = _Py_Specialize_CallNoKw(
call_shape.callable, next_instr, nargs, callable, next_instr, nargs,
call_shape.kwnames, cache, BUILTINS()); call_shape.kwnames, cache, BUILTINS());
if (err < 0) { if (err < 0) {
goto error; goto error;
@ -4627,7 +4621,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
else { else {
STAT_INC(CALL, deferred); STAT_INC(CALL, deferred);
cache->adaptive.counter--; cache->adaptive.counter--;
oparg = named_args; oparg = original_oparg;
goto call_function; goto call_function;
} }
} }
@ -4635,10 +4629,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_PY_EXACT_ARGS) { TARGET(CALL_PY_EXACT_ARGS) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE(); SpecializedCacheEntry *caches = GET_CACHE();
int argcount = call_shape.total_args; int original_oparg = caches->adaptive.original_oparg;
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL); 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; _PyCallCache *cache1 = &caches[-1].call;
PyFunctionObject *func = (PyFunctionObject *)call_shape.callable; PyFunctionObject *func = (PyFunctionObject *)callable;
DEOPT_IF(func->func_version != cache1->func_version, CALL); DEOPT_IF(func->func_version != cache1->func_version, CALL);
PyCodeObject *code = (PyCodeObject *)func->func_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
DEOPT_IF(code->co_argcount != argcount, CALL); 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++) { for (int i = argcount; i < code->co_nlocalsplus; i++) {
new_frame->localsplus[i] = NULL; new_frame->localsplus[i] = NULL;
} }
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = frame; new_frame->previous = frame;
frame = cframe.current_frame = new_frame; frame = cframe.current_frame = new_frame;
@ -4664,10 +4661,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_PY_WITH_DEFAULTS) { TARGET(CALL_PY_WITH_DEFAULTS) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE(); SpecializedCacheEntry *caches = GET_CACHE();
int argcount = call_shape.total_args; int original_oparg = caches->adaptive.original_oparg;
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL); 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; _PyCallCache *cache1 = &caches[-1].call;
PyFunctionObject *func = (PyFunctionObject *)call_shape.callable; PyFunctionObject *func = (PyFunctionObject *)callable;
DEOPT_IF(func->func_version != cache1->func_version, CALL); DEOPT_IF(func->func_version != cache1->func_version, CALL);
PyCodeObject *code = (PyCodeObject *)func->func_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
DEOPT_IF(argcount > code->co_argcount, CALL); 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++) { for (int i = code->co_argcount; i < code->co_nlocalsplus; i++) {
new_frame->localsplus[i] = NULL; new_frame->localsplus[i] = NULL;
} }
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = frame; new_frame->previous = frame;
frame = cframe.current_frame = new_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) { TARGET(CALL_NO_KW_TYPE_1) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
assert(cframe.use_tracing == 0); 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 *obj = TOP();
PyObject *callable = SECOND(); PyObject *callable = SECOND();
DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL); DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL);
PyObject *res = Py_NewRef(Py_TYPE(obj)); PyObject *res = Py_NewRef(Py_TYPE(obj));
Py_DECREF(callable); Py_DECREF(callable);
Py_DECREF(obj); Py_DECREF(obj);
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2);
SET_TOP(res); SET_TOP(res);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
@ -4716,16 +4717,18 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW_STR_1) { TARGET(CALL_NO_KW_STR_1) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
DEOPT_IF(!PyType_Check(call_shape.callable), CALL); assert(GET_CACHE()->adaptive.original_oparg == 1);
PyTypeObject *tp = (PyTypeObject *)call_shape.callable; PyObject *callable = PEEK(2);
DEOPT_IF(call_shape.total_args != 1, CALL); DEOPT_IF(!PyType_Check(callable), CALL);
PyTypeObject *tp = (PyTypeObject *)callable;
DEOPT_IF(is_method(stack_pointer, 1), CALL);
DEOPT_IF(tp != &PyUnicode_Type, CALL); DEOPT_IF(tp != &PyUnicode_Type, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
PyObject *arg = TOP(); PyObject *arg = TOP();
PyObject *res = PyObject_Str(arg); PyObject *res = PyObject_Str(arg);
Py_DECREF(arg); Py_DECREF(arg);
Py_DECREF(&PyUnicode_Type); Py_DECREF(&PyUnicode_Type);
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2);
SET_TOP(res); SET_TOP(res);
if (res == NULL) { if (res == NULL) {
goto error; goto error;
@ -4736,16 +4739,19 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW_TUPLE_1) { TARGET(CALL_NO_KW_TUPLE_1) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
DEOPT_IF(!PyType_Check(call_shape.callable), CALL); assert(GET_CACHE()->adaptive.original_oparg == 1);
PyTypeObject *tp = (PyTypeObject *)call_shape.callable; int is_meth = is_method(stack_pointer, 1);
DEOPT_IF(call_shape.total_args != 1, CALL); 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); DEOPT_IF(tp != &PyTuple_Type, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
PyObject *arg = TOP(); PyObject *arg = TOP();
PyObject *res = PySequence_Tuple(arg); PyObject *res = PySequence_Tuple(arg);
Py_DECREF(arg); Py_DECREF(arg);
Py_DECREF(&PyTuple_Type); Py_DECREF(&PyTuple_Type);
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2);
SET_TOP(res); SET_TOP(res);
if (res == NULL) { if (res == NULL) {
goto error; goto error;
@ -4755,22 +4761,25 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
} }
TARGET(CALL_BUILTIN_CLASS) { TARGET(CALL_BUILTIN_CLASS) {
DEOPT_IF(!PyType_Check(call_shape.callable), CALL); int original_oparg = GET_CACHE()->adaptive.original_oparg;
PyTypeObject *tp = (PyTypeObject *)call_shape.callable; 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); DEOPT_IF(tp->tp_vectorcall == NULL, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
int kwnames_len = GET_CACHE()->adaptive.original_oparg; STACK_SHRINK(total_args);
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer,
int nargs = call_shape.total_args - kwnames_len; total_args-kwnames_len, call_shape.kwnames);
STACK_SHRINK(call_shape.total_args);
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, nargs, call_shape.kwnames);
call_shape.kwnames = NULL; call_shape.kwnames = NULL;
/* Free the arguments. */ /* 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(stack_pointer[i]);
} }
Py_DECREF(tp); Py_DECREF(tp);
STACK_SHRINK(call_shape.postcall_shrink-1); STACK_SHRINK(1-is_meth);
SET_TOP(res); SET_TOP(res);
if (res == NULL) { if (res == NULL) {
goto error; goto error;
@ -4783,8 +4792,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
/* Builtin METH_O functions */ /* Builtin METH_O functions */
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
DEOPT_IF(call_shape.total_args != 1, CALL); SpecializedCacheEntry *caches = GET_CACHE();
PyObject *callable = call_shape.callable; 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_CheckExact(callable), CALL);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL); DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
@ -4802,7 +4815,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
Py_DECREF(arg); Py_DECREF(arg);
Py_DECREF(callable); Py_DECREF(callable);
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
SET_TOP(res); SET_TOP(res);
if (res == NULL) { if (res == NULL) {
goto error; goto error;
@ -4815,27 +4828,30 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
/* Builtin METH_FASTCALL functions, without keywords */ /* Builtin METH_FASTCALL functions, without keywords */
assert(call_shape.kwnames == NULL); 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_CheckExact(callable), CALL);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL,
CALL); CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
int nargs = call_shape.total_args;
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
STACK_SHRINK(nargs); STACK_SHRINK(total_args);
/* res = func(self, args, nargs) */ /* res = func(self, args, nargs) */
PyObject *res = ((_PyCFunctionFast)(void(*)(void))cfunc)( PyObject *res = ((_PyCFunctionFast)(void(*)(void))cfunc)(
PyCFunction_GET_SELF(callable), PyCFunction_GET_SELF(callable),
stack_pointer, stack_pointer,
nargs); total_args);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
/* Free the arguments. */ /* Free the arguments. */
for (int i = 0; i < nargs; i++) { for (int i = 0; i < total_args; i++) {
Py_DECREF(stack_pointer[i]); Py_DECREF(stack_pointer[i]);
} }
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
PUSH(res); PUSH(res);
Py_DECREF(callable); Py_DECREF(callable);
if (res == NULL) { if (res == NULL) {
@ -4853,19 +4869,16 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) { TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */ /* 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_CheckExact(callable), CALL);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != DEOPT_IF(PyCFunction_GET_FLAGS(callable) !=
(METH_FASTCALL | METH_KEYWORDS), CALL); (METH_FASTCALL | METH_KEYWORDS), CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
int kwnames_len = GET_CACHE()->adaptive.original_oparg; STACK_SHRINK(total_args);
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);
/* res = func(self, args, nargs, kwnames) */ /* res = func(self, args, nargs, kwnames) */
_PyCFunctionFastWithKeywords cfunc = _PyCFunctionFastWithKeywords cfunc =
(_PyCFunctionFastWithKeywords)(void(*)(void)) (_PyCFunctionFastWithKeywords)(void(*)(void))
@ -4873,17 +4886,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PyObject *res = cfunc( PyObject *res = cfunc(
PyCFunction_GET_SELF(callable), PyCFunction_GET_SELF(callable),
stack_pointer, stack_pointer,
nargs, total_args - KWNAMES_LEN(),
call_shape.kwnames call_shape.kwnames
); );
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
call_shape.kwnames = NULL; call_shape.kwnames = NULL;
/* Free the arguments. */ /* 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(stack_pointer[i]);
} }
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
PUSH(res); PUSH(res);
Py_DECREF(callable); Py_DECREF(callable);
if (res == NULL) { if (res == NULL) {
@ -4898,11 +4911,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
/* len(o) */ /* len(o) */
SpecializedCacheEntry *caches = GET_CACHE(); SpecializedCacheEntry *caches = GET_CACHE();
DEOPT_IF(call_shape.total_args != 1, CALL); int original_oparg = caches->adaptive.original_oparg;
assert(caches[0].adaptive.original_oparg == 0); 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; _PyObjectCache *cache1 = &caches[-1].obj;
PyObject *callable = PEEK(total_args + 1);
PyObject *callable = call_shape.callable;
DEOPT_IF(callable != cache1->obj, CALL); DEOPT_IF(callable != cache1->obj, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
@ -4914,7 +4928,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PyObject *res = PyLong_FromSsize_t(len_i); PyObject *res = PyLong_FromSsize_t(len_i);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
SET_TOP(res); SET_TOP(res);
Py_DECREF(callable); Py_DECREF(callable);
Py_DECREF(arg); Py_DECREF(arg);
@ -4929,11 +4943,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
/* isinstance(o, o2) */ /* isinstance(o, o2) */
SpecializedCacheEntry *caches = GET_CACHE(); SpecializedCacheEntry *caches = GET_CACHE();
assert(caches[0].adaptive.original_oparg == 0); int original_oparg = caches->adaptive.original_oparg;
DEOPT_IF(call_shape.total_args != 2, 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);
_PyObjectCache *cache1 = &caches[-1].obj; _PyObjectCache *cache1 = &caches[-1].obj;
DEOPT_IF(call_shape.callable != cache1->obj, CALL); DEOPT_IF(callable != cache1->obj, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
PyObject *cls = POP(); PyObject *cls = POP();
@ -4946,11 +4963,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
PyObject *res = PyBool_FromLong(retval); PyObject *res = PyBool_FromLong(retval);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
SET_TOP(res); SET_TOP(res);
Py_DECREF(inst); Py_DECREF(inst);
Py_DECREF(cls); Py_DECREF(cls);
Py_DECREF(call_shape.callable); Py_DECREF(callable);
if (res == NULL) { if (res == NULL) {
goto error; goto error;
} }
@ -4961,9 +4978,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
SpecializedCacheEntry *caches = GET_CACHE(); SpecializedCacheEntry *caches = GET_CACHE();
int original_oparg = caches->adaptive.original_oparg;
_PyObjectCache *cache1 = &caches[-1].obj; _PyObjectCache *cache1 = &caches[-1].obj;
DEOPT_IF(call_shape.total_args != 2, CALL); int is_meth = is_method(stack_pointer, original_oparg);
DEOPT_IF(call_shape.callable != cache1->obj, CALL); 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(); PyObject *list = SECOND();
DEOPT_IF(!PyList_Check(list), CALL); DEOPT_IF(!PyList_Check(list), CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
@ -4974,18 +4995,22 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
} }
Py_DECREF(arg); Py_DECREF(arg);
Py_DECREF(list); Py_DECREF(list);
STACK_SHRINK(call_shape.postcall_shrink+1); STACK_SHRINK(3-is_meth);
Py_INCREF(Py_None); Py_INCREF(Py_None);
SET_TOP(Py_None); SET_TOP(Py_None);
Py_DECREF(call_shape.callable); Py_DECREF(callable);
NOTRACE_DISPATCH(); NOTRACE_DISPATCH();
} }
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
DEOPT_IF(call_shape.total_args != 2, CALL); int original_oparg = GET_CACHE()->adaptive.original_oparg;
DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL); int is_meth = is_method(stack_pointer, original_oparg);
PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method; 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); DEOPT_IF(meth->ml_flags != METH_O, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth; PyCFunction cfunc = meth->ml_meth;
@ -5001,9 +5026,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
Py_DECREF(self); Py_DECREF(self);
Py_DECREF(arg); Py_DECREF(arg);
STACK_SHRINK(call_shape.postcall_shrink+1); STACK_SHRINK(3-is_meth);
SET_TOP(res); SET_TOP(res);
Py_DECREF(call_shape.callable); Py_DECREF(callable);
if (res == NULL) { if (res == NULL) {
goto error; goto error;
} }
@ -5013,9 +5038,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) {
assert(call_shape.kwnames == NULL); assert(call_shape.kwnames == NULL);
DEOPT_IF(call_shape.total_args != 1, CALL); int original_oparg = GET_CACHE()->adaptive.original_oparg;
DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL); int is_meth = is_method(stack_pointer, original_oparg);
PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method; 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); DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
PyCFunction cfunc = meth->ml_meth; PyCFunction cfunc = meth->ml_meth;
@ -5029,9 +5058,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
_Py_LeaveRecursiveCall(tstate); _Py_LeaveRecursiveCall(tstate);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
Py_DECREF(self); Py_DECREF(self);
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
SET_TOP(res); SET_TOP(res);
Py_DECREF(call_shape.callable); Py_DECREF(callable);
if (res == NULL) { if (res == NULL) {
goto error; goto error;
} }
@ -5041,13 +5070,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) {
assert(call_shape.kwnames == NULL); 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 */ /* Builtin METH_FASTCALL methods, without keywords */
DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL); DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method; PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL); DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL);
STAT_INC(CALL, hit); STAT_INC(CALL, hit);
_PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth; _PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth;
int nargs = call_shape.total_args-1; int nargs = total_args-1;
STACK_SHRINK(nargs); STACK_SHRINK(nargs);
PyObject *self = TOP(); PyObject *self = TOP();
PyObject *res = cfunc(self, stack_pointer, nargs); 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(stack_pointer[i]);
} }
Py_DECREF(self); Py_DECREF(self);
STACK_SHRINK(call_shape.postcall_shrink); STACK_SHRINK(2-is_meth);
SET_TOP(res); SET_TOP(res);
Py_DECREF(call_shape.callable); Py_DECREF(callable);
if (res == NULL) { if (res == NULL) {
goto error; 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_LOAD_CONST(c, Py_None); ADDOP_LOAD_CONST(c, Py_None);
ADDOP_I(c, PRECALL, 2); ADDOP_I(c, PRECALL, 2);
ADDOP_I(c, CALL, 0); ADDOP_I(c, CALL, 2);
return 1; return 1;
} }
@ -4679,16 +4679,12 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
if (kwdsl) { if (kwdsl) {
VISIT_SEQ(c, keyword, kwds); VISIT_SEQ(c, keyword, kwds);
ADDOP_I(c, PRECALL, argsl + kwdsl);
if (!compiler_call_simple_kw_helper(c, kwds, kwdsl)) { if (!compiler_call_simple_kw_helper(c, kwds, kwdsl)) {
return 0; 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; c->u->u_lineno = old_lineno;
return 1; return 1;
} }
@ -4758,7 +4754,7 @@ compiler_joined_str(struct compiler *c, expr_ty e)
ADDOP_I(c, LIST_APPEND, 1); ADDOP_I(c, LIST_APPEND, 1);
} }
ADDOP_I(c, PRECALL, 1); ADDOP_I(c, PRECALL, 1);
ADDOP_I(c, CALL, 0); ADDOP_I(c, CALL, 1);
} }
else { else {
VISIT_SEQ(c, expr, e->v.JoinedStr.values); VISIT_SEQ(c, expr, e->v.JoinedStr.values);
@ -4927,18 +4923,13 @@ compiler_call_helper(struct compiler *c,
} }
if (nkwelts) { if (nkwelts) {
VISIT_SEQ(c, keyword, keywords); VISIT_SEQ(c, keyword, keywords);
ADDOP_I(c, PRECALL, n + nelts + nkwelts);
if (!compiler_call_simple_kw_helper(c, keywords, nkwelts)) { if (!compiler_call_simple_kw_helper(c, keywords, nkwelts)) {
return 0; 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: ex_call: