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 @@ _code_type = type(_write_atomic.__code__)
# 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 @@ _code_type = type(_write_atomic.__code__)
# 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 @@ dis_f = """\
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 @@ dis_f_co_code = """\
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 @@ dis_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 @@ dis_annot_stmt_str = """\
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 @@ dis_annot_stmt_str = """\
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 @@ expected_opinfo_outer = [
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 @@ expected_opinfo_f = [
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 @@ expected_opinfo_inner = [
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 @@ expected_opinfo_jumpy = [
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 @@ expected_opinfo_jumpy = [
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 @@ expected_opinfo_jumpy = [
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 @@ expected_opinfo_jumpy = [
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 @@ expected_opinfo_jumpy = [
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 @@ expected_opinfo_jumpy = [
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 @@ expected_opinfo_jumpy = [
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 @@ expected_opinfo_jumpy = [
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 @@ expected_opinfo_jumpy = [
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 @@ expected_opinfo_jumpy = [
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
} }
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
} }
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
_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 @@ handle_eval_breaker:
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 @@ handle_eval_breaker:
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: