diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst index ef64f75ce9f..003d79864cb 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 85f50eb958e..5255d7e19ce 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -386,6 +386,7 @@ _code_type = type(_write_atomic.__code__) # 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 @@ _code_type = type(_write_atomic.__code__) # 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 0ab2556da2f..e81c834878f 100644 --- a/Lib/test/test_dis.py +++ b/Lib/test/test_dis.py @@ -109,7 +109,7 @@ dis_f = """\ 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 @@ dis_f_co_code = """\ LOAD_GLOBAL 0 LOAD_FAST 0 PRECALL 1 - CALL 0 + CALL 1 POP_TOP LOAD_CONST 1 RETURN_VALUE @@ -147,7 +147,7 @@ dis_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 @@ dis_annot_stmt_str = """\ 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 @@ dis_annot_stmt_str = """\ 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 @@ 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='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 @@ 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=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 @@ 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=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 @@ 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_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 @@ 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_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 @@ 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_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 @@ 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_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 @@ 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_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 @@ 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_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 @@ 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_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 @@ 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_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 @@ 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_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 @@ 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_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 00000000000..c04db946028 --- /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 a7f6b6022a4..11593a9ba3d 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 471bbde46f9..d3ab1da76de 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: else { STAT_INC(CALL, deferred); cache->adaptive.counter--; - oparg = named_args; + oparg = original_oparg; goto call_function; } } @@ -4635,10 +4629,13 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: } 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: } 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: _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 @@ handle_eval_breaker: 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 @@ handle_eval_breaker: 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 645213b192e..7f0a6f096d7 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: