[Python-checkins] bpo-46329: Streamline calling sequence a bit. (GH-31465)

markshannon webhook-mailer at python.org
Mon Feb 21 13:26:57 EST 2022


https://github.com/python/cpython/commit/59585d6b2ea50d7bc3a9b336da5bde61367f527c
commit: 59585d6b2ea50d7bc3a9b336da5bde61367f527c
branch: main
author: Mark Shannon <mark at hotpy.org>
committer: markshannon <mark at hotpy.org>
date: 2022-02-21T18:26:47Z
summary:

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

files:
A Misc/NEWS.d/next/Core and Builtins/2022-02-21-10-29-20.bpo-46329.cbkt7u.rst
M Doc/library/dis.rst
M Lib/importlib/_bootstrap_external.py
M Lib/test/test_dis.py
M Programs/test_frozenmain.h
M Python/ceval.c
M Python/compile.c

diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index ef64f75ce9f83..003d79864cbf0 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -36,11 +36,12 @@ the following command can be used to display the disassembly of
    >>> dis.dis(myfunc)
      1           0 RESUME                   0
 
-     2           2 LOAD_GLOBAL              0 (len)
-                 4 LOAD_FAST                0 (alist)
-                 6 PRECALL_FUNCTION         1
-                 8 CALL                     0
-                10 RETURN_VALUE
+     2           2 PUSH_NULL
+                 4 LOAD_GLOBAL              0 (len)
+                 6 LOAD_FAST                0 (alist)
+                 8 PRECALL                  1
+                10 CALL                     1
+                12 RETURN_VALUE
 
 (The "2" is a line number).
 
@@ -106,9 +107,10 @@ Example::
     ...     print(instr.opname)
     ...
     RESUME
+    PUSH_NULL
     LOAD_GLOBAL
     LOAD_FAST
-    PRECALL_FUNCTION
+    PRECALL
     CALL
     RETURN_VALUE
 
@@ -1063,18 +1065,28 @@ iterations of the loop.
      with ``__cause__`` set to ``TOS``)
 
 
-.. opcode:: CALL (named)
+.. opcode:: CALL (argc)
 
-   Calls a callable object with the number of positional arguments specified by
-   the preceding :opcode:`PRECALL_FUNCTION` or :opcode:`PRECALL_METHOD` and
-   the named arguments specified by the preceding :opcode:`KW_NAMES`, if any.
-   *named* indicates the number of named arguments.
-   On the stack are (in ascending order):
+   Calls a callable object with the number of arguments specified by ``argc``,
+   including the named arguments specified by the preceding
+   :opcode:`KW_NAMES`, if any.
+   On the stack are (in ascending order), either:
 
+   * NULL
    * The callable
    * The positional arguments
    * The named arguments
 
+   or:
+
+   * The callable
+   * ``self``
+   * The remaining positional arguments
+   * The named arguments
+
+   ``argc`` is the total of the positional and named arguments, excluding
+   ``self`` when a ``NULL`` is not present.
+
    ``CALL`` pops all arguments and the callable object off the stack,
    calls the callable object with those arguments, and pushes the return value
    returned by the callable object.
@@ -1102,33 +1114,34 @@ iterations of the loop.
    Loads a method named ``co_names[namei]`` from the TOS object. TOS is popped.
    This bytecode distinguishes two cases: if TOS has a method with the correct
    name, the bytecode pushes the unbound method and TOS. TOS will be used as
-   the first argument (``self``) by :opcode:`PRECALL_METHOD` when calling the
+   the first argument (``self``) by :opcode:`CALL` when calling the
    unbound method. Otherwise, ``NULL`` and the object return by the attribute
    lookup are pushed.
 
    .. versionadded:: 3.7
 
 
-.. opcode:: PRECALL_METHOD (argc)
+.. opcode:: PRECALL (argc)
 
-   Prefixes :opcode:`CALL` (possibly with an intervening ``KW_NAMES``).
-   This opcode is designed to be used with :opcode:`LOAD_METHOD`.
-   Sets internal variables, so that :opcode:`CALL`
-   clean up after :opcode:`LOAD_METHOD` correctly.
+   Prefixes :opcode:`CALL`. Logically this is a no op.
+   It exists to enable effective specialization of calls.
+   ``argc`` is the number of arguments as described in :opcode:`CALL`.
 
    .. versionadded:: 3.11
 
 
-.. opcode:: PRECALL_FUNCTION (args)
+.. opcode:: PUSH_NULL
 
-   Prefixes :opcode:`CALL` (possibly with an intervening ``KW_NAMES``).
-   Sets internal variables, so that :opcode:`CALL` can execute correctly.
+    Pushes a ``NULL`` to the stack.
+    Used in the call sequence to match the ``NULL`` pushed by
+    :opcode:`LOAD_METHOD` for non-method calls.
 
    .. versionadded:: 3.11
 
 
 .. opcode:: KW_NAMES (i)
 
+   Prefixes :opcode:`PRECALL`.
    Stores a reference to ``co_consts[consti]`` into an internal variable
    for use by :opcode:`CALL`. ``co_consts[consti]`` must be a tuple of strings.
 
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index 85f50eb958e31..5255d7e19ce8e 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -386,6 +386,7 @@ def _write_atomic(path, data, mode=0o666):
 #                         ROT_TWO/ROT_THREE/ROT_FOUR/ROT_N with SWAP)
 #     Python 3.11a5 3478 (New CALL opcodes)
 #     Python 3.11a5 3479 (Add PUSH_NULL opcode)
+#     Python 3.11a5 3480 (New CALL opcodes, second iteration)
 
 #     Python 3.12 will start with magic number 3500
 
@@ -403,7 +404,7 @@ def _write_atomic(path, data, mode=0o666):
 # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
 # in PC/launcher.c must also be updated.
 
-MAGIC_NUMBER = (3479).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3480).to_bytes(2, 'little') + b'\r\n'
 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c
 
 _PYCACHE = '__pycache__'
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 0ab2556da2f4f..e81c834878f08 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -109,7 +109,7 @@ def _f(a):
            LOAD_GLOBAL              0 (print)
            LOAD_FAST                0 (a)
            PRECALL                  1
-           CALL                     0
+           CALL                     1
            POP_TOP
 
 %3d        LOAD_CONST               1 (1)
@@ -125,7 +125,7 @@ def _f(a):
        LOAD_GLOBAL              0
        LOAD_FAST                0
        PRECALL                  1
-       CALL                     0
+       CALL                     1
        POP_TOP
        LOAD_CONST               1
        RETURN_VALUE
@@ -147,7 +147,7 @@ def bug708901():
 %3d        LOAD_CONST               2 (10)
 
 %3d        PRECALL                  2
-           CALL                     0
+           CALL                     2
            GET_ITER
         >> FOR_ITER                 2 (to 22)
            STORE_FAST               0 (res)
@@ -319,7 +319,7 @@ def bug42562():
            LOAD_NAME                3 (fun)
            LOAD_CONST               0 (1)
            PRECALL                  1
-           CALL                     0
+           CALL                     1
            LOAD_NAME                2 (__annotations__)
            LOAD_CONST               2 ('y')
            STORE_SUBSCR
@@ -330,7 +330,7 @@ def bug42562():
            LOAD_NAME                3 (fun)
            LOAD_CONST               3 (0)
            PRECALL                  1
-           CALL                     0
+           CALL                     1
            STORE_SUBSCR
            LOAD_NAME                1 (int)
            POP_TOP
@@ -1164,7 +1164,7 @@ def _prepare_test_cases():
   Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Hello world!', argrepr="'Hello world!'", offset=36, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=7, argval=7, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=7, argval=7, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=44, starts_line=8, is_jump_target=False, positions=None),
   Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None),
@@ -1191,7 +1191,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=34, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=36, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=4, argval=4, argrepr='', offset=38, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=4, argval=4, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=42, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=44, starts_line=6, is_jump_target=False, positions=None),
   Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=46, starts_line=None, is_jump_target=False, positions=None),
@@ -1209,7 +1209,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=16, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=18, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=6, argval=6, argrepr='', offset=20, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=6, argval=6, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=24, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=26, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None),
@@ -1221,7 +1221,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=4, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=6, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=8, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=10, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=10, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=12, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='FOR_ITER', opcode=93, arg=19, argval=54, argrepr='to 54', offset=14, starts_line=None, is_jump_target=True, positions=None),
   Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=16, starts_line=None, is_jump_target=False, positions=None),
@@ -1229,7 +1229,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=20, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=22, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=24, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=26, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=30, starts_line=5, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=32, starts_line=None, is_jump_target=False, positions=None),
@@ -1247,7 +1247,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=56, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=58, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=64, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=66, starts_line=11, is_jump_target=True, positions=None),
   Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=57, argval=114, argrepr='to 114', offset=68, starts_line=None, is_jump_target=False, positions=None),
@@ -1255,7 +1255,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=72, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=74, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=76, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=78, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=78, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=80, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=82, starts_line=13, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=84, starts_line=None, is_jump_target=False, positions=None),
@@ -1277,7 +1277,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=116, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Who let lolcatz into this test suite?', argrepr="'Who let lolcatz into this test suite?'", offset=118, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=120, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=122, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=124, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=126, starts_line=20, is_jump_target=True, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=128, starts_line=21, is_jump_target=False, positions=None),
@@ -1291,13 +1291,13 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=144, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Never reach this', argrepr="'Never reach this'", offset=146, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=148, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=150, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=152, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=154, starts_line=25, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=156, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=158, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=2, argval=2, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=2, argval=2, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=190, argrepr='to 190', offset=166, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None),
@@ -1320,7 +1320,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=202, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=204, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=206, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=208, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='JUMP_FORWARD', opcode=110, arg=12, argval=240, argrepr='to 240', offset=214, starts_line=None, is_jump_target=False, positions=None),
@@ -1332,7 +1332,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=226, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=228, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=232, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=234, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=236, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=238, starts_line=None, is_jump_target=False, positions=None),
@@ -1341,7 +1341,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=244, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=246, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=248, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=250, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=252, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=254, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=256, starts_line=None, is_jump_target=False, positions=None),
@@ -1350,7 +1350,7 @@ def _prepare_test_cases():
   Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=262, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=264, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='PRECALL', opcode=166, arg=1, argval=1, argrepr='', offset=266, starts_line=None, is_jump_target=False, positions=None),
-  Instruction(opname='CALL', opcode=171, arg=0, argval=0, argrepr='', offset=268, starts_line=None, is_jump_target=False, positions=None),
+  Instruction(opname='CALL', opcode=171, arg=1, argval=1, argrepr='', offset=268, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=270, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=272, starts_line=None, is_jump_target=False, positions=None),
   Instruction(opname='COPY', opcode=120, arg=3, argval=3, argrepr='', offset=274, starts_line=None, is_jump_target=False, positions=None),
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-02-21-10-29-20.bpo-46329.cbkt7u.rst b/Misc/NEWS.d/next/Core and Builtins/2022-02-21-10-29-20.bpo-46329.cbkt7u.rst
new file mode 100644
index 0000000000000..c04db9460283e
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-02-21-10-29-20.bpo-46329.cbkt7u.rst	
@@ -0,0 +1,2 @@
+Move ``KW_NAMES`` before ``PRECALL`` instruction in call sequence. Change
+``operand`` of ``CALL`` to match ``PRECALL`` for easier specialization.
diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h
index a7f6b6022a49e..11593a9ba3d68 100644
--- a/Programs/test_frozenmain.h
+++ b/Programs/test_frozenmain.h
@@ -3,11 +3,11 @@ unsigned char M_test_frozenmain[] = {
     227,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,
     0,0,0,0,0,115,104,0,0,0,151,0,100,0,100,1,
     108,0,90,0,100,0,100,1,108,1,90,1,2,0,101,2,
-    100,2,166,1,171,0,1,0,2,0,101,2,100,3,101,0,
-    106,3,166,2,171,0,1,0,2,0,101,1,106,4,166,0,
+    100,2,166,1,171,1,1,0,2,0,101,2,100,3,101,0,
+    106,3,166,2,171,2,1,0,2,0,101,1,106,4,166,0,
     171,0,100,4,25,0,90,5,100,5,68,0,93,16,90,6,
     2,0,101,2,100,6,101,6,155,0,100,7,101,5,101,6,
-    25,0,155,0,157,4,166,1,171,0,1,0,113,33,100,1,
+    25,0,155,0,157,4,166,1,171,1,1,0,113,33,100,1,
     83,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122,
     101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8,
     115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103,
diff --git a/Python/ceval.c b/Python/ceval.c
index 471bbde46f9db..d3ab1da76dea4 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1585,15 +1585,19 @@ pop_frame(PyThreadState *tstate, InterpreterFrame *frame)
 }
 
 /* It is only between the PRECALL instruction and the following CALL,
- * that these values have any meaning.
+ * that this has any meaning.
  */
 typedef struct {
-    PyObject *callable;
     PyObject *kwnames;
-    int total_args;
-    int postcall_shrink;
 } CallShape;
 
+static inline bool
+is_method(PyObject **stack_pointer, int args) {
+    return PEEK(args+2) != NULL;
+}
+
+#define KWNAMES_LEN() \
+    (call_shape.kwnames == NULL ? 0 : ((int)PyTuple_GET_SIZE(call_shape.kwnames)))
 
 PyObject* _Py_HOT_FUNCTION
 _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag)
@@ -1616,11 +1620,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
     CFrame cframe;
     CallShape call_shape;
     call_shape.kwnames = NULL; // Borrowed reference. Reset by CALL instructions.
-    /* The following three values are always set by the PRECALL instructions.
-       They are set here to keep the compiler happy. */
-    call_shape.postcall_shrink = 0;
-    call_shape.total_args = 0;
-    call_shape.callable = NULL; // Strong reference
 
     /* WARNING: Because the CFrame lives on the C stack,
      * but can be accessed from a heap allocated object (tstate)
@@ -4513,23 +4512,31 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             int nargs = oparg + is_method;
             /* Move ownership of reference from stack to call_shape
              * and make sure that NULL is cleared from stack */
-            call_shape.callable = PEEK(nargs + 1);
-            call_shape.postcall_shrink = 2-is_method;
-
-            call_shape.total_args = nargs;
-            assert(call_shape.kwnames == NULL);
+            PyObject *function = PEEK(nargs + 1);
 #ifdef Py_STATS
             extern int _PySpecialization_ClassifyCallable(PyObject *);
             SpecializationStats *stats =
                 &_py_stats.opcode_stats[PRECALL].specialization;
             stats->failure++;
-            int kind = _PySpecialization_ClassifyCallable(call_shape.callable);
+            int kind = _PySpecialization_ClassifyCallable(function);
             stats->failure_kinds[kind]++;
 #endif
+            if (!is_method && Py_TYPE(function) == &PyMethod_Type) {
+                PyObject *meth = ((PyMethodObject *)function)->im_func;
+                PyObject *self = ((PyMethodObject *)function)->im_self;
+                Py_INCREF(meth);
+                Py_INCREF(self);
+                PEEK(oparg+1) = self;
+                PEEK(oparg+2) = meth;
+                Py_DECREF(function);
+                function = meth;
+            }
+
             DISPATCH();
         }
 
         TARGET(KW_NAMES) {
+            assert(call_shape.kwnames == NULL);
             assert(oparg < PyTuple_GET_SIZE(consts));
             call_shape.kwnames = GETITEM(consts, oparg);
             DISPATCH();
@@ -4537,25 +4544,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
         TARGET(CALL) {
             PREDICTED(CALL);
-            PyObject *function;
-            assert((oparg == 0 && call_shape.kwnames == NULL)
-                || (oparg != 0 && oparg == PyTuple_GET_SIZE(call_shape.kwnames)));
+            int is_meth;
         call_function:
-            function = call_shape.callable;
-            if (Py_TYPE(function) == &PyMethod_Type) {
-                PyObject *meth = ((PyMethodObject *)function)->im_func;
-                PyObject *self = ((PyMethodObject *)function)->im_self;
-                Py_INCREF(meth);
-                Py_INCREF(self);
-                PEEK(call_shape.total_args + 1) = self;
-                Py_DECREF(function);
-                function = meth;
-                call_shape.total_args++;
-                assert(call_shape.postcall_shrink >= 1);
-                call_shape.postcall_shrink--;
-            }
-            int total_args = call_shape.total_args;
-            int positional_args = total_args - oparg;
+            is_meth = is_method(stack_pointer, oparg);
+            int total_args = oparg + is_meth;
+            PyObject *function = PEEK(total_args + 1);
+            int positional_args = total_args - KWNAMES_LEN();
             // Check if the call can be inlined or not
             if (Py_TYPE(function) == &PyFunction_Type && tstate->interp->eval_frame == NULL) {
                 int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(function))->co_flags;
@@ -4566,7 +4560,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
                     stack_pointer, positional_args, call_shape.kwnames
                 );
                 call_shape.kwnames = NULL;
-                STACK_SHRINK(call_shape.postcall_shrink);
+                STACK_SHRINK(2-is_meth);
                 // The frame has stolen all the arguments from the stack,
                 // so there is no need to clean them up.
                 if (new_frame == NULL) {
@@ -4599,7 +4593,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             for (int i = 0; i < total_args; i++) {
                 Py_DECREF(stack_pointer[i]);
             }
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             PUSH(res);
             if (res == NULL) {
                 goto error;
@@ -4610,14 +4604,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
         TARGET(CALL_ADAPTIVE) {
             SpecializedCacheEntry *cache = GET_CACHE();
-            int named_args = cache->adaptive.original_oparg;
-            assert((named_args == 0 && call_shape.kwnames == NULL)
-                || (named_args != 0 && named_args == PyTuple_GET_SIZE(call_shape.kwnames)));
+            int original_oparg = cache->adaptive.original_oparg;
             if (cache->adaptive.counter == 0) {
                 next_instr--;
-                int nargs = call_shape.total_args;
+                int is_meth = is_method(stack_pointer, original_oparg);
+                int nargs = original_oparg + is_meth;
+                PyObject *callable = PEEK(nargs + 1);
                 int err = _Py_Specialize_CallNoKw(
-                    call_shape.callable, next_instr, nargs,
+                    callable, next_instr, nargs,
                     call_shape.kwnames, cache, BUILTINS());
                 if (err < 0) {
                     goto error;
@@ -4627,7 +4621,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             else {
                 STAT_INC(CALL, deferred);
                 cache->adaptive.counter--;
-                oparg = named_args;
+                oparg = original_oparg;
                 goto call_function;
             }
         }
@@ -4635,10 +4629,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
         TARGET(CALL_PY_EXACT_ARGS) {
             assert(call_shape.kwnames == NULL);
             SpecializedCacheEntry *caches = GET_CACHE();
-            int argcount = call_shape.total_args;
-            DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
+            int original_oparg = caches->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int argcount = original_oparg + is_meth;
+            PyObject *callable = PEEK(argcount + 1);
+            DEOPT_IF(!PyFunction_Check(callable), CALL);
             _PyCallCache *cache1 = &caches[-1].call;
-            PyFunctionObject *func = (PyFunctionObject *)call_shape.callable;
+            PyFunctionObject *func = (PyFunctionObject *)callable;
             DEOPT_IF(func->func_version != cache1->func_version, CALL);
             PyCodeObject *code = (PyCodeObject *)func->func_code;
             DEOPT_IF(code->co_argcount != argcount, CALL);
@@ -4654,7 +4651,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             for (int i = argcount; i < code->co_nlocalsplus; i++) {
                 new_frame->localsplus[i] = NULL;
             }
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             _PyFrame_SetStackPointer(frame, stack_pointer);
             new_frame->previous = frame;
             frame = cframe.current_frame = new_frame;
@@ -4664,10 +4661,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
         TARGET(CALL_PY_WITH_DEFAULTS) {
             assert(call_shape.kwnames == NULL);
             SpecializedCacheEntry *caches = GET_CACHE();
-            int argcount = call_shape.total_args;
-            DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
+            int original_oparg = caches->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int argcount = original_oparg + is_meth;
+            PyObject *callable = PEEK(argcount + 1);
+            DEOPT_IF(!PyFunction_Check(callable), CALL);
             _PyCallCache *cache1 = &caches[-1].call;
-            PyFunctionObject *func = (PyFunctionObject *)call_shape.callable;
+            PyFunctionObject *func = (PyFunctionObject *)callable;
             DEOPT_IF(func->func_version != cache1->func_version, CALL);
             PyCodeObject *code = (PyCodeObject *)func->func_code;
             DEOPT_IF(argcount > code->co_argcount, CALL);
@@ -4691,7 +4691,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             for (int i = code->co_argcount; i < code->co_nlocalsplus; i++) {
                 new_frame->localsplus[i] = NULL;
             }
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             _PyFrame_SetStackPointer(frame, stack_pointer);
             new_frame->previous = frame;
             frame = cframe.current_frame = new_frame;
@@ -4701,14 +4701,15 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
         TARGET(CALL_NO_KW_TYPE_1) {
             assert(call_shape.kwnames == NULL);
             assert(cframe.use_tracing == 0);
-            DEOPT_IF(call_shape.total_args != 1, CALL);
+            assert(GET_CACHE()->adaptive.original_oparg == 1);
+            DEOPT_IF(is_method(stack_pointer, 1), CALL);
             PyObject *obj = TOP();
             PyObject *callable = SECOND();
             DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL);
             PyObject *res = Py_NewRef(Py_TYPE(obj));
             Py_DECREF(callable);
             Py_DECREF(obj);
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2);
             SET_TOP(res);
             NOTRACE_DISPATCH();
         }
@@ -4716,16 +4717,18 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
         TARGET(CALL_NO_KW_STR_1) {
             assert(call_shape.kwnames == NULL);
             assert(cframe.use_tracing == 0);
-            DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
-            PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
-            DEOPT_IF(call_shape.total_args != 1, CALL);
+            assert(GET_CACHE()->adaptive.original_oparg == 1);
+            PyObject *callable = PEEK(2);
+            DEOPT_IF(!PyType_Check(callable), CALL);
+            PyTypeObject *tp = (PyTypeObject *)callable;
+            DEOPT_IF(is_method(stack_pointer, 1), CALL);
             DEOPT_IF(tp != &PyUnicode_Type, CALL);
             STAT_INC(CALL, hit);
             PyObject *arg = TOP();
             PyObject *res = PyObject_Str(arg);
             Py_DECREF(arg);
             Py_DECREF(&PyUnicode_Type);
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2);
             SET_TOP(res);
             if (res == NULL) {
                 goto error;
@@ -4736,16 +4739,19 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
         TARGET(CALL_NO_KW_TUPLE_1) {
             assert(call_shape.kwnames == NULL);
-            DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
-            PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
-            DEOPT_IF(call_shape.total_args != 1, CALL);
+            assert(GET_CACHE()->adaptive.original_oparg == 1);
+            int is_meth = is_method(stack_pointer, 1);
+            PyObject *callable = PEEK(2);
+            DEOPT_IF(!PyType_Check(callable), CALL);
+            PyTypeObject *tp = (PyTypeObject *)callable;
+            DEOPT_IF(is_meth, CALL);
             DEOPT_IF(tp != &PyTuple_Type, CALL);
             STAT_INC(CALL, hit);
             PyObject *arg = TOP();
             PyObject *res = PySequence_Tuple(arg);
             Py_DECREF(arg);
             Py_DECREF(&PyTuple_Type);
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2);
             SET_TOP(res);
             if (res == NULL) {
                 goto error;
@@ -4755,22 +4761,25 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
         }
 
         TARGET(CALL_BUILTIN_CLASS) {
-            DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
-            PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
+            int original_oparg = GET_CACHE()->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            int kwnames_len = KWNAMES_LEN();
+            PyObject *callable = PEEK(total_args + 1);
+            DEOPT_IF(!PyType_Check(callable), CALL);
+            PyTypeObject *tp = (PyTypeObject *)callable;
             DEOPT_IF(tp->tp_vectorcall == NULL, CALL);
             STAT_INC(CALL, hit);
-            int kwnames_len = GET_CACHE()->adaptive.original_oparg;
-
-            int nargs = call_shape.total_args - kwnames_len;
-            STACK_SHRINK(call_shape.total_args);
-            PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, nargs, call_shape.kwnames);
+            STACK_SHRINK(total_args);
+            PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer,
+                                              total_args-kwnames_len, call_shape.kwnames);
             call_shape.kwnames = NULL;
             /* Free the arguments. */
-            for (int i = 0; i < call_shape.total_args; i++) {
+            for (int i = 0; i < total_args; i++) {
                 Py_DECREF(stack_pointer[i]);
             }
             Py_DECREF(tp);
-            STACK_SHRINK(call_shape.postcall_shrink-1);
+            STACK_SHRINK(1-is_meth);
             SET_TOP(res);
             if (res == NULL) {
                 goto error;
@@ -4783,8 +4792,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             assert(cframe.use_tracing == 0);
             /* Builtin METH_O functions */
             assert(call_shape.kwnames == NULL);
-            DEOPT_IF(call_shape.total_args != 1, CALL);
-            PyObject *callable = call_shape.callable;
+            SpecializedCacheEntry *caches = GET_CACHE();
+            int original_oparg = caches->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            DEOPT_IF(total_args != 1, CALL);
+            PyObject *callable = PEEK(total_args + 1);
             DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
             DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL);
             STAT_INC(CALL, hit);
@@ -4802,7 +4815,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
             Py_DECREF(arg);
             Py_DECREF(callable);
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             SET_TOP(res);
             if (res == NULL) {
                 goto error;
@@ -4815,27 +4828,30 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             assert(cframe.use_tracing == 0);
             /* Builtin METH_FASTCALL functions, without keywords */
             assert(call_shape.kwnames == NULL);
-            PyObject *callable = call_shape.callable;
+            SpecializedCacheEntry *caches = GET_CACHE();
+            int original_oparg = caches->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            PyObject *callable = PEEK(total_args + 1);
             DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
             DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL,
                 CALL);
             STAT_INC(CALL, hit);
 
-            int nargs = call_shape.total_args;
             PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
-            STACK_SHRINK(nargs);
+            STACK_SHRINK(total_args);
             /* res = func(self, args, nargs) */
             PyObject *res = ((_PyCFunctionFast)(void(*)(void))cfunc)(
                 PyCFunction_GET_SELF(callable),
                 stack_pointer,
-                nargs);
+                total_args);
             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
 
             /* Free the arguments. */
-            for (int i = 0; i < nargs; i++) {
+            for (int i = 0; i < total_args; i++) {
                 Py_DECREF(stack_pointer[i]);
             }
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             PUSH(res);
             Py_DECREF(callable);
             if (res == NULL) {
@@ -4853,19 +4869,16 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
         TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) {
             assert(cframe.use_tracing == 0);
             /* Builtin METH_FASTCALL | METH_KEYWORDS functions */
-            PyObject *callable = call_shape.callable;
+            SpecializedCacheEntry *caches = GET_CACHE();
+            int original_oparg = caches->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            PyObject *callable = PEEK(total_args + 1);
             DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
             DEOPT_IF(PyCFunction_GET_FLAGS(callable) !=
                 (METH_FASTCALL | METH_KEYWORDS), CALL);
             STAT_INC(CALL, hit);
-            int kwnames_len = GET_CACHE()->adaptive.original_oparg;
-            assert(
-                (call_shape.kwnames == NULL && kwnames_len == 0) ||
-                (call_shape.kwnames != NULL &&
-                 PyTuple_GET_SIZE(call_shape.kwnames) == kwnames_len)
-            );
-            int nargs = call_shape.total_args - kwnames_len;
-            STACK_SHRINK(call_shape.total_args);
+            STACK_SHRINK(total_args);
             /* res = func(self, args, nargs, kwnames) */
             _PyCFunctionFastWithKeywords cfunc =
                 (_PyCFunctionFastWithKeywords)(void(*)(void))
@@ -4873,17 +4886,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             PyObject *res = cfunc(
                 PyCFunction_GET_SELF(callable),
                 stack_pointer,
-                nargs,
+                total_args - KWNAMES_LEN(),
                 call_shape.kwnames
             );
             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
             call_shape.kwnames = NULL;
 
             /* Free the arguments. */
-            for (int i = 0; i < call_shape.total_args; i++) {
+            for (int i = 0; i < total_args; i++) {
                 Py_DECREF(stack_pointer[i]);
             }
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             PUSH(res);
             Py_DECREF(callable);
             if (res == NULL) {
@@ -4898,11 +4911,12 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             assert(call_shape.kwnames == NULL);
             /* len(o) */
             SpecializedCacheEntry *caches = GET_CACHE();
-            DEOPT_IF(call_shape.total_args != 1, CALL);
-            assert(caches[0].adaptive.original_oparg == 0);
+            int original_oparg = caches->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            DEOPT_IF(total_args != 1, CALL);
             _PyObjectCache *cache1 = &caches[-1].obj;
-
-            PyObject *callable = call_shape.callable;
+            PyObject *callable = PEEK(total_args + 1);
             DEOPT_IF(callable != cache1->obj, CALL);
             STAT_INC(CALL, hit);
 
@@ -4914,7 +4928,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             PyObject *res = PyLong_FromSsize_t(len_i);
             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
 
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             SET_TOP(res);
             Py_DECREF(callable);
             Py_DECREF(arg);
@@ -4929,11 +4943,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             assert(call_shape.kwnames == NULL);
             /* isinstance(o, o2) */
             SpecializedCacheEntry *caches = GET_CACHE();
-            assert(caches[0].adaptive.original_oparg == 0);
-            DEOPT_IF(call_shape.total_args != 2, CALL);
+            int original_oparg = caches->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            PyObject *callable = PEEK(total_args + 1);
+            DEOPT_IF(total_args != 2, CALL);
             _PyObjectCache *cache1 = &caches[-1].obj;
 
-            DEOPT_IF(call_shape.callable != cache1->obj, CALL);
+            DEOPT_IF(callable != cache1->obj, CALL);
             STAT_INC(CALL, hit);
 
             PyObject *cls = POP();
@@ -4946,11 +4963,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             PyObject *res = PyBool_FromLong(retval);
             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
 
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             SET_TOP(res);
             Py_DECREF(inst);
             Py_DECREF(cls);
-            Py_DECREF(call_shape.callable);
+            Py_DECREF(callable);
             if (res == NULL) {
                 goto error;
             }
@@ -4961,9 +4978,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             assert(cframe.use_tracing == 0);
             assert(call_shape.kwnames == NULL);
             SpecializedCacheEntry *caches = GET_CACHE();
+            int original_oparg = caches->adaptive.original_oparg;
             _PyObjectCache *cache1 = &caches[-1].obj;
-            DEOPT_IF(call_shape.total_args != 2, CALL);
-            DEOPT_IF(call_shape.callable != cache1->obj, CALL);
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            PyObject *callable = PEEK(total_args + 1);
+            DEOPT_IF(total_args != 2, CALL);
+            DEOPT_IF(callable != cache1->obj, CALL);
             PyObject *list = SECOND();
             DEOPT_IF(!PyList_Check(list), CALL);
             STAT_INC(CALL, hit);
@@ -4974,18 +4995,22 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             }
             Py_DECREF(arg);
             Py_DECREF(list);
-            STACK_SHRINK(call_shape.postcall_shrink+1);
+            STACK_SHRINK(3-is_meth);
             Py_INCREF(Py_None);
             SET_TOP(Py_None);
-            Py_DECREF(call_shape.callable);
+            Py_DECREF(callable);
             NOTRACE_DISPATCH();
         }
 
         TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) {
             assert(call_shape.kwnames == NULL);
-            DEOPT_IF(call_shape.total_args != 2, CALL);
-            DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL);
-            PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method;
+            int original_oparg = GET_CACHE()->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            PyObject *callable = PEEK(total_args + 1);
+            DEOPT_IF(total_args != 2, CALL);
+            DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
+            PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
             DEOPT_IF(meth->ml_flags != METH_O, CALL);
             STAT_INC(CALL, hit);
             PyCFunction cfunc = meth->ml_meth;
@@ -5001,9 +5026,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
             Py_DECREF(self);
             Py_DECREF(arg);
-            STACK_SHRINK(call_shape.postcall_shrink+1);
+            STACK_SHRINK(3-is_meth);
             SET_TOP(res);
-            Py_DECREF(call_shape.callable);
+            Py_DECREF(callable);
             if (res == NULL) {
                 goto error;
             }
@@ -5013,9 +5038,13 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
         TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) {
             assert(call_shape.kwnames == NULL);
-            DEOPT_IF(call_shape.total_args != 1, CALL);
-            DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL);
-            PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method;
+            int original_oparg = GET_CACHE()->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            PyObject *callable = PEEK(total_args + 1);
+            DEOPT_IF(total_args != 1, CALL);
+            DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
+            PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
             DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL);
             STAT_INC(CALL, hit);
             PyCFunction cfunc = meth->ml_meth;
@@ -5029,9 +5058,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
             _Py_LeaveRecursiveCall(tstate);
             assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
             Py_DECREF(self);
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             SET_TOP(res);
-            Py_DECREF(call_shape.callable);
+            Py_DECREF(callable);
             if (res == NULL) {
                 goto error;
             }
@@ -5041,13 +5070,17 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
 
         TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) {
             assert(call_shape.kwnames == NULL);
+            int original_oparg = GET_CACHE()->adaptive.original_oparg;
+            int is_meth = is_method(stack_pointer, original_oparg);
+            int total_args = original_oparg + is_meth;
+            PyObject *callable = PEEK(total_args + 1);
             /* Builtin METH_FASTCALL methods, without keywords */
-            DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL);
-            PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method;
+            DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
+            PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
             DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL);
             STAT_INC(CALL, hit);
             _PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth;
-            int nargs = call_shape.total_args-1;
+            int nargs = total_args-1;
             STACK_SHRINK(nargs);
             PyObject *self = TOP();
             PyObject *res = cfunc(self, stack_pointer, nargs);
@@ -5057,9 +5090,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
                 Py_DECREF(stack_pointer[i]);
             }
             Py_DECREF(self);
-            STACK_SHRINK(call_shape.postcall_shrink);
+            STACK_SHRINK(2-is_meth);
             SET_TOP(res);
-            Py_DECREF(call_shape.callable);
+            Py_DECREF(callable);
             if (res == NULL) {
                 goto error;
             }
diff --git a/Python/compile.c b/Python/compile.c
index 645213b192eae..7f0a6f096d723 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1800,7 +1800,7 @@ compiler_call_exit_with_nones(struct compiler *c) {
     ADDOP_LOAD_CONST(c, Py_None);
     ADDOP_LOAD_CONST(c, Py_None);
     ADDOP_I(c, PRECALL, 2);
-    ADDOP_I(c, CALL, 0);
+    ADDOP_I(c, CALL, 2);
     return 1;
 }
 
@@ -4679,16 +4679,12 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
 
     if (kwdsl) {
         VISIT_SEQ(c, keyword, kwds);
-        ADDOP_I(c, PRECALL, argsl + kwdsl);
         if (!compiler_call_simple_kw_helper(c, kwds, kwdsl)) {
             return 0;
         };
-        ADDOP_I(c, CALL, kwdsl);
-    }
-    else {
-        ADDOP_I(c, PRECALL, argsl);
-        ADDOP_I(c, CALL, 0);
     }
+    ADDOP_I(c, PRECALL, argsl + kwdsl);
+    ADDOP_I(c, CALL, argsl + kwdsl);
     c->u->u_lineno = old_lineno;
     return 1;
 }
@@ -4758,7 +4754,7 @@ compiler_joined_str(struct compiler *c, expr_ty e)
             ADDOP_I(c, LIST_APPEND, 1);
         }
         ADDOP_I(c, PRECALL, 1);
-        ADDOP_I(c, CALL, 0);
+        ADDOP_I(c, CALL, 1);
     }
     else {
         VISIT_SEQ(c, expr, e->v.JoinedStr.values);
@@ -4927,18 +4923,13 @@ compiler_call_helper(struct compiler *c,
     }
     if (nkwelts) {
         VISIT_SEQ(c, keyword, keywords);
-        ADDOP_I(c, PRECALL, n + nelts + nkwelts);
         if (!compiler_call_simple_kw_helper(c, keywords, nkwelts)) {
             return 0;
         };
-        ADDOP_I(c, CALL, nkwelts);
-        return 1;
-    }
-    else {
-        ADDOP_I(c, PRECALL, n + nelts);
-        ADDOP_I(c, CALL, 0);
-        return 1;
     }
+    ADDOP_I(c, PRECALL, n + nelts + nkwelts);
+    ADDOP_I(c, CALL, n + nelts + nkwelts);
+    return 1;
 
 ex_call:
 



More information about the Python-checkins mailing list