bpo-44525: Split calls into PRECALL and CALL (GH-30011)

* Add 3 new opcodes for calls: PRECALL_METHOD, CALL_NO_KW, CALL_KW.

* Update specialization to handle new CALL opcodes.

* Specialize call to method descriptors.

* Remove old CALL opcodes: CALL_FUNCTION, CALL_METHOD, CALL_METHOD_KW, CALL_FUNCTION_KW.
This commit is contained in:
Mark Shannon 2021-12-14 18:22:44 +00:00 committed by GitHub
parent d60457a667
commit 9f8f45144b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 395 additions and 236 deletions

View File

@ -36,7 +36,7 @@ the following command can be used to display the disassembly of
>>> dis.dis(myfunc) >>> dis.dis(myfunc)
2 0 LOAD_GLOBAL 0 (len) 2 0 LOAD_GLOBAL 0 (len)
2 LOAD_FAST 0 (alist) 2 LOAD_FAST 0 (alist)
4 CALL_FUNCTION 1 4 CALL_NO_KW 1
6 RETURN_VALUE 6 RETURN_VALUE
(The "2" is a line number). (The "2" is a line number).
@ -104,7 +104,7 @@ Example::
... ...
LOAD_GLOBAL LOAD_GLOBAL
LOAD_FAST LOAD_FAST
CALL_FUNCTION CALL_NO_KW
RETURN_VALUE RETURN_VALUE
@ -616,7 +616,7 @@ iterations of the loop.
.. opcode:: LOAD_BUILD_CLASS .. opcode:: LOAD_BUILD_CLASS
Pushes :func:`builtins.__build_class__` onto the stack. It is later called Pushes :func:`builtins.__build_class__` onto the stack. It is later called
by :opcode:`CALL_FUNCTION` to construct a class. by :opcode:`CALL_NO_KW` to construct a class.
.. opcode:: BEFORE_WITH (delta) .. opcode:: BEFORE_WITH (delta)
@ -1039,21 +1039,20 @@ All of the following opcodes use their arguments.
with ``__cause__`` set to ``TOS``) with ``__cause__`` set to ``TOS``)
.. opcode:: CALL_FUNCTION (argc) .. opcode:: CALL_NO_KW (argc)
Calls a callable object with positional arguments. Calls a callable object with positional arguments.
*argc* indicates the number of positional arguments. *argc* indicates the number of positional arguments.
The top of the stack contains positional arguments, with the right-most The top of the stack contains positional arguments, with the right-most
argument on top. Below the arguments is a callable object to call. argument on top. Below the arguments is a callable object to call.
``CALL_FUNCTION`` pops all arguments and the callable object off the stack, ``CALL_NO_KW`` pops all arguments and the callable object off the stack,
calls the callable object with those arguments, and pushes the return value calls the callable object with those arguments, and pushes the return value
returned by the callable object. returned by the callable object.
.. versionchanged:: 3.6 .. versionadded:: 3.11
This opcode is used only for calls with positional arguments.
.. opcode:: CALL_FUNCTION_KW (argc) .. opcode:: CALL_KW (argc)
Calls a callable object with positional (if any) and keyword arguments. Calls a callable object with positional (if any) and keyword arguments.
*argc* indicates the total number of positional and keyword arguments. *argc* indicates the total number of positional and keyword arguments.
@ -1063,13 +1062,11 @@ All of the following opcodes use their arguments.
in the order corresponding to the tuple. in the order corresponding to the tuple.
Below that are positional arguments, with the right-most parameter on Below that are positional arguments, with the right-most parameter on
top. Below the arguments is a callable object to call. top. Below the arguments is a callable object to call.
``CALL_FUNCTION_KW`` pops all arguments and the callable object off the stack, ``CALL_KW`` pops all arguments and the callable object off the stack,
calls the callable object with those arguments, and pushes the return value calls the callable object with those arguments, and pushes the return value
returned by the callable object. returned by the callable object.
.. versionchanged:: 3.6 .. versionadded:: 3.11
Keyword arguments are packed in a tuple instead of a dictionary,
*argc* indicates the total number of arguments.
.. opcode:: CALL_FUNCTION_EX (flags) .. opcode:: CALL_FUNCTION_EX (flags)
@ -1099,30 +1096,16 @@ All of the following opcodes use their arguments.
.. versionadded:: 3.7 .. versionadded:: 3.7
.. opcode:: CALL_METHOD (argc) .. opcode:: PRECALL_METHOD (argc)
Calls a method. *argc* is the number of positional arguments. Prefixes either :opcode:`CALL_NO_KW` or :opcode:`CALL_KW`.
Keyword arguments are not supported. This opcode is designed to be used This opcode is designed to be used with :opcode:`LOAD_METHOD`.
with :opcode:`LOAD_METHOD`. Positional arguments are on top of the stack. Sets internal variables, so that :opcode:`CALL_NO_KW` or :opcode:`CALL_KW`
Below them, the two items described in :opcode:`LOAD_METHOD` are on the clean up after :opcode:`LOAD_METHOD` correctly.
stack (either ``self`` and an unbound method object or ``NULL`` and an
arbitrary callable). All of them are popped and the return value is pushed.
.. versionadded:: 3.7
.. opcode:: CALL_METHOD_KW (argc)
Calls a method in a similar fashion as :opcode:`CALL_METHOD`, but also supports keyword arguments.
*argc* is the number of positional and keyword arguments.
This opcode is designed to be used with :opcode:`LOAD_METHOD`. TOS is a
tuple of keyword argument names. Argument values are below that.
Below them, the two items described in :opcode:`LOAD_METHOD` are on the
stack (either ``self`` and an unbound method object or ``NULL`` and an
arbitrary callable). All of them are popped from the stack and the return value is pushed.
.. versionadded:: 3.11 .. versionadded:: 3.11
.. opcode:: MAKE_FUNCTION (flags) .. opcode:: MAKE_FUNCTION (flags)
Pushes a new function object on the stack. From bottom to top, the consumed Pushes a new function object on the stack. From bottom to top, the consumed

View File

@ -271,7 +271,7 @@ int _Py_Specialize_LoadGlobal(PyObject *globals, PyObject *builtins, _Py_CODEUNI
int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache); int _Py_Specialize_LoadMethod(PyObject *owner, _Py_CODEUNIT *instr, PyObject *name, SpecializedCacheEntry *cache);
int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); int _Py_Specialize_BinarySubscr(PyObject *sub, PyObject *container, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache);
int _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr); int _Py_Specialize_StoreSubscr(PyObject *container, PyObject *sub, _Py_CODEUNIT *instr);
int _Py_Specialize_CallFunction(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache, PyObject *builtins); int _Py_Specialize_CallNoKw(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SpecializedCacheEntry *cache, PyObject *builtins);
void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, void _Py_Specialize_BinaryOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
SpecializedCacheEntry *cache); SpecializedCacheEntry *cache);
void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache); void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr, SpecializedCacheEntry *cache);
@ -288,7 +288,7 @@ void _Py_Specialize_CompareOp(PyObject *lhs, PyObject *rhs, _Py_CODEUNIT *instr,
#define COLLECT_SPECIALIZATION_STATS_DETAILED PRINT_SPECIALIZATION_STATS_DETAILED #define COLLECT_SPECIALIZATION_STATS_DETAILED PRINT_SPECIALIZATION_STATS_DETAILED
#endif #endif
#define SPECIALIZATION_FAILURE_KINDS 20 #define SPECIALIZATION_FAILURE_KINDS 30
#if COLLECT_SPECIALIZATION_STATS #if COLLECT_SPECIALIZATION_STATS

68
Include/opcode.h generated
View File

@ -87,7 +87,6 @@ extern "C" {
#define JUMP_IF_NOT_EG_MATCH 127 #define JUMP_IF_NOT_EG_MATCH 127
#define GEN_START 129 #define GEN_START 129
#define RAISE_VARARGS 130 #define RAISE_VARARGS 130
#define CALL_FUNCTION 131
#define MAKE_FUNCTION 132 #define MAKE_FUNCTION 132
#define BUILD_SLICE 133 #define BUILD_SLICE 133
#define MAKE_CELL 135 #define MAKE_CELL 135
@ -95,7 +94,6 @@ extern "C" {
#define LOAD_DEREF 137 #define LOAD_DEREF 137
#define STORE_DEREF 138 #define STORE_DEREF 138
#define DELETE_DEREF 139 #define DELETE_DEREF 139
#define CALL_FUNCTION_KW 141
#define CALL_FUNCTION_EX 142 #define CALL_FUNCTION_EX 142
#define EXTENDED_ARG 144 #define EXTENDED_ARG 144
#define LIST_APPEND 145 #define LIST_APPEND 145
@ -108,12 +106,13 @@ extern "C" {
#define BUILD_CONST_KEY_MAP 156 #define BUILD_CONST_KEY_MAP 156
#define BUILD_STRING 157 #define BUILD_STRING 157
#define LOAD_METHOD 160 #define LOAD_METHOD 160
#define CALL_METHOD 161
#define LIST_EXTEND 162 #define LIST_EXTEND 162
#define SET_UPDATE 163 #define SET_UPDATE 163
#define DICT_MERGE 164 #define DICT_MERGE 164
#define DICT_UPDATE 165 #define DICT_UPDATE 165
#define CALL_METHOD_KW 166 #define PRECALL_METHOD 168
#define CALL_NO_KW 169
#define CALL_KW 170
#define BINARY_OP_ADAPTIVE 7 #define BINARY_OP_ADAPTIVE 7
#define BINARY_OP_ADD_INT 8 #define BINARY_OP_ADD_INT 8
#define BINARY_OP_ADD_FLOAT 13 #define BINARY_OP_ADD_FLOAT 13
@ -135,35 +134,38 @@ extern "C" {
#define STORE_SUBSCR_ADAPTIVE 36 #define STORE_SUBSCR_ADAPTIVE 36
#define STORE_SUBSCR_LIST_INT 38 #define STORE_SUBSCR_LIST_INT 38
#define STORE_SUBSCR_DICT 39 #define STORE_SUBSCR_DICT 39
#define CALL_FUNCTION_ADAPTIVE 40 #define CALL_NO_KW_ADAPTIVE 40
#define CALL_FUNCTION_BUILTIN_O 41 #define CALL_NO_KW_BUILTIN_O 41
#define CALL_FUNCTION_BUILTIN_FAST 42 #define CALL_NO_KW_BUILTIN_FAST 42
#define CALL_FUNCTION_LEN 43 #define CALL_NO_KW_LEN 43
#define CALL_FUNCTION_ISINSTANCE 44 #define CALL_NO_KW_ISINSTANCE 44
#define CALL_FUNCTION_PY_SIMPLE 45 #define CALL_NO_KW_PY_SIMPLE 45
#define JUMP_ABSOLUTE_QUICK 46 #define CALL_NO_KW_LIST_APPEND 46
#define LOAD_ATTR_ADAPTIVE 47 #define CALL_NO_KW_METHOD_DESCRIPTOR_O 47
#define LOAD_ATTR_INSTANCE_VALUE 48 #define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 48
#define LOAD_ATTR_WITH_HINT 55 #define JUMP_ABSOLUTE_QUICK 55
#define LOAD_ATTR_SLOT 56 #define LOAD_ATTR_ADAPTIVE 56
#define LOAD_ATTR_MODULE 57 #define LOAD_ATTR_INSTANCE_VALUE 57
#define LOAD_GLOBAL_ADAPTIVE 58 #define LOAD_ATTR_WITH_HINT 58
#define LOAD_GLOBAL_MODULE 59 #define LOAD_ATTR_SLOT 59
#define LOAD_GLOBAL_BUILTIN 62 #define LOAD_ATTR_MODULE 62
#define LOAD_METHOD_ADAPTIVE 63 #define LOAD_GLOBAL_ADAPTIVE 63
#define LOAD_METHOD_CACHED 64 #define LOAD_GLOBAL_MODULE 64
#define LOAD_METHOD_CLASS 65 #define LOAD_GLOBAL_BUILTIN 65
#define LOAD_METHOD_MODULE 66 #define LOAD_METHOD_ADAPTIVE 66
#define LOAD_METHOD_NO_DICT 67 #define LOAD_METHOD_CACHED 67
#define STORE_ATTR_ADAPTIVE 75 #define LOAD_METHOD_CLASS 75
#define STORE_ATTR_INSTANCE_VALUE 76 #define LOAD_METHOD_MODULE 76
#define STORE_ATTR_SLOT 77 #define LOAD_METHOD_NO_DICT 77
#define STORE_ATTR_WITH_HINT 78 #define STORE_ATTR_ADAPTIVE 78
#define LOAD_FAST__LOAD_FAST 79 #define STORE_ATTR_INSTANCE_VALUE 79
#define STORE_FAST__LOAD_FAST 80 #define STORE_ATTR_SLOT 80
#define LOAD_FAST__LOAD_CONST 81 #define STORE_ATTR_WITH_HINT 81
#define LOAD_CONST__LOAD_FAST 87 #define LOAD_FAST__LOAD_FAST 87
#define STORE_FAST__STORE_FAST 123 #define STORE_FAST__LOAD_FAST 123
#define LOAD_FAST__LOAD_CONST 128
#define LOAD_CONST__LOAD_FAST 131
#define STORE_FAST__STORE_FAST 134
#define DO_TRACING 255 #define DO_TRACING 255
#ifdef NEED_OPCODE_JUMP_TABLES #ifdef NEED_OPCODE_JUMP_TABLES
static uint32_t _PyOpcode_RelativeJump[8] = { static uint32_t _PyOpcode_RelativeJump[8] = {

View File

@ -372,6 +372,7 @@ _code_type = type(_write_atomic.__code__)
# BINARY_OP) # BINARY_OP)
# Python 3.11a3 3465 (Add COPY_FREE_VARS opcode) # Python 3.11a3 3465 (Add COPY_FREE_VARS opcode)
# Python 3.11a3 3466 (bpo-45292: PEP-654 except*) # Python 3.11a3 3466 (bpo-45292: PEP-654 except*)
# Python 3.11a4 3467 (Change CALL_xxx opcodes)
# #
# MAGIC must change whenever the bytecode emitted by the compiler may no # MAGIC must change whenever the bytecode emitted by the compiler may no
@ -381,7 +382,7 @@ _code_type = type(_write_atomic.__code__)
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
# in PC/launcher.c must also be updated. # in PC/launcher.c must also be updated.
MAGIC_NUMBER = (3466).to_bytes(2, 'little') + b'\r\n' MAGIC_NUMBER = (3467).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
_PYCACHE = '__pycache__' _PYCACHE = '__pycache__'

View File

@ -155,7 +155,7 @@ jabs_op('JUMP_IF_NOT_EG_MATCH', 127)
def_op('GEN_START', 129) # Kind of generator/coroutine def_op('GEN_START', 129) # Kind of generator/coroutine
def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3) def_op('RAISE_VARARGS', 130) # Number of raise arguments (1, 2, or 3)
def_op('CALL_FUNCTION', 131) # #args
def_op('MAKE_FUNCTION', 132) # Flags def_op('MAKE_FUNCTION', 132) # Flags
def_op('BUILD_SLICE', 133) # Number of items def_op('BUILD_SLICE', 133) # Number of items
@ -170,7 +170,6 @@ hasfree.append(138)
def_op('DELETE_DEREF', 139) def_op('DELETE_DEREF', 139)
hasfree.append(139) hasfree.append(139)
def_op('CALL_FUNCTION_KW', 141) # #args + #kwargs
def_op('CALL_FUNCTION_EX', 142) # Flags def_op('CALL_FUNCTION_EX', 142) # Flags
def_op('EXTENDED_ARG', 144) def_op('EXTENDED_ARG', 144)
@ -189,12 +188,15 @@ def_op('BUILD_CONST_KEY_MAP', 156)
def_op('BUILD_STRING', 157) def_op('BUILD_STRING', 157)
name_op('LOAD_METHOD', 160) name_op('LOAD_METHOD', 160)
def_op('CALL_METHOD', 161)
def_op('LIST_EXTEND', 162) def_op('LIST_EXTEND', 162)
def_op('SET_UPDATE', 163) def_op('SET_UPDATE', 163)
def_op('DICT_MERGE', 164) def_op('DICT_MERGE', 164)
def_op('DICT_UPDATE', 165) def_op('DICT_UPDATE', 165)
def_op('CALL_METHOD_KW', 166)
def_op('PRECALL_METHOD', 168)
def_op('CALL_NO_KW', 169)
def_op('CALL_KW', 170)
del def_op, name_op, jrel_op, jabs_op del def_op, name_op, jrel_op, jabs_op
@ -249,12 +251,15 @@ _specialized_instructions = [
"STORE_SUBSCR_ADAPTIVE", "STORE_SUBSCR_ADAPTIVE",
"STORE_SUBSCR_LIST_INT", "STORE_SUBSCR_LIST_INT",
"STORE_SUBSCR_DICT", "STORE_SUBSCR_DICT",
"CALL_FUNCTION_ADAPTIVE", "CALL_NO_KW_ADAPTIVE",
"CALL_FUNCTION_BUILTIN_O", "CALL_NO_KW_BUILTIN_O",
"CALL_FUNCTION_BUILTIN_FAST", "CALL_NO_KW_BUILTIN_FAST",
"CALL_FUNCTION_LEN", "CALL_NO_KW_LEN",
"CALL_FUNCTION_ISINSTANCE", "CALL_NO_KW_ISINSTANCE",
"CALL_FUNCTION_PY_SIMPLE", "CALL_NO_KW_PY_SIMPLE",
"CALL_NO_KW_LIST_APPEND",
"CALL_NO_KW_METHOD_DESCRIPTOR_O",
"CALL_NO_KW_METHOD_DESCRIPTOR_FAST",
"JUMP_ABSOLUTE_QUICK", "JUMP_ABSOLUTE_QUICK",
"LOAD_ATTR_ADAPTIVE", "LOAD_ATTR_ADAPTIVE",
"LOAD_ATTR_INSTANCE_VALUE", "LOAD_ATTR_INSTANCE_VALUE",

View File

@ -839,7 +839,7 @@ if 1:
self.assertNotIn('LOAD_METHOD', instructions) self.assertNotIn('LOAD_METHOD', instructions)
self.assertNotIn('CALL_METHOD', instructions) self.assertNotIn('CALL_METHOD', instructions)
self.assertIn('LOAD_ATTR', instructions) self.assertIn('LOAD_ATTR', instructions)
self.assertIn('CALL_FUNCTION', instructions) self.assertIn('CALL_NO_KW', instructions)
def test_lineno_procedure_call(self): def test_lineno_procedure_call(self):
def call(): def call():
@ -1095,7 +1095,7 @@ f(
) )
""" """
compiled_code, _ = self.check_positions_against_ast(snippet) compiled_code, _ = self.check_positions_against_ast(snippet)
self.assertOpcodeSourcePositionIs(compiled_code, 'CALL_FUNCTION', self.assertOpcodeSourcePositionIs(compiled_code, 'CALL_NO_KW',
line=1, end_line=3, column=0, end_column=1) line=1, end_line=3, column=0, end_column=1)
def test_very_long_line_end_offset(self): def test_very_long_line_end_offset(self):
@ -1105,7 +1105,7 @@ f(
snippet = f"g('{long_string}')" snippet = f"g('{long_string}')"
compiled_code, _ = self.check_positions_against_ast(snippet) compiled_code, _ = self.check_positions_against_ast(snippet)
self.assertOpcodeSourcePositionIs(compiled_code, 'CALL_FUNCTION', self.assertOpcodeSourcePositionIs(compiled_code, 'CALL_NO_KW',
line=1, end_line=1, column=None, end_column=None) line=1, end_line=1, column=None, end_column=None)
def test_complex_single_line_expression(self): def test_complex_single_line_expression(self):

View File

@ -95,7 +95,7 @@ def _f(a):
dis_f = """\ dis_f = """\
%3d 0 LOAD_GLOBAL 0 (print) %3d 0 LOAD_GLOBAL 0 (print)
2 LOAD_FAST 0 (a) 2 LOAD_FAST 0 (a)
4 CALL_FUNCTION 1 4 CALL_NO_KW 1
6 POP_TOP 6 POP_TOP
%3d 8 LOAD_CONST 1 (1) %3d 8 LOAD_CONST 1 (1)
@ -107,7 +107,7 @@ dis_f = """\
dis_f_co_code = """\ dis_f_co_code = """\
0 LOAD_GLOBAL 0 0 LOAD_GLOBAL 0
2 LOAD_FAST 0 2 LOAD_FAST 0
4 CALL_FUNCTION 1 4 CALL_NO_KW 1
6 POP_TOP 6 POP_TOP
8 LOAD_CONST 1 8 LOAD_CONST 1
10 RETURN_VALUE 10 RETURN_VALUE
@ -125,7 +125,7 @@ dis_bug708901 = """\
%3d 4 LOAD_CONST 2 (10) %3d 4 LOAD_CONST 2 (10)
%3d 6 CALL_FUNCTION 2 %3d 6 CALL_NO_KW 2
8 GET_ITER 8 GET_ITER
>> 10 FOR_ITER 2 (to 16) >> 10 FOR_ITER 2 (to 16)
12 STORE_FAST 0 (res) 12 STORE_FAST 0 (res)
@ -152,12 +152,12 @@ dis_bug1333982 = """\
4 MAKE_FUNCTION 0 4 MAKE_FUNCTION 0
6 LOAD_FAST 0 (x) 6 LOAD_FAST 0 (x)
8 GET_ITER 8 GET_ITER
10 CALL_FUNCTION 1 10 CALL_NO_KW 1
%3d 12 LOAD_CONST 3 (1) %3d 12 LOAD_CONST 3 (1)
%3d 14 BINARY_OP 0 (+) %3d 14 BINARY_OP 0 (+)
16 CALL_FUNCTION 1 16 CALL_NO_KW 1
18 RAISE_VARARGS 1 18 RAISE_VARARGS 1
""" % (bug1333982.__code__.co_firstlineno + 1, """ % (bug1333982.__code__.co_firstlineno + 1,
__file__, __file__,
@ -260,7 +260,7 @@ dis_annot_stmt_str = """\
3 14 LOAD_NAME 3 (fun) 3 14 LOAD_NAME 3 (fun)
16 LOAD_CONST 0 (1) 16 LOAD_CONST 0 (1)
18 CALL_FUNCTION 1 18 CALL_NO_KW 1
20 LOAD_NAME 2 (__annotations__) 20 LOAD_NAME 2 (__annotations__)
22 LOAD_CONST 2 ('y') 22 LOAD_CONST 2 ('y')
24 STORE_SUBSCR 24 STORE_SUBSCR
@ -269,7 +269,7 @@ dis_annot_stmt_str = """\
28 LOAD_NAME 4 (lst) 28 LOAD_NAME 4 (lst)
30 LOAD_NAME 3 (fun) 30 LOAD_NAME 3 (fun)
32 LOAD_CONST 3 (0) 32 LOAD_CONST 3 (0)
34 CALL_FUNCTION 1 34 CALL_NO_KW 1
36 STORE_SUBSCR 36 STORE_SUBSCR
38 LOAD_NAME 1 (int) 38 LOAD_NAME 1 (int)
40 POP_TOP 40 POP_TOP
@ -384,12 +384,12 @@ dis_tryfinally = """\
%3d 2 LOAD_FAST 0 (a) %3d 2 LOAD_FAST 0 (a)
%3d 4 LOAD_FAST 1 (b) %3d 4 LOAD_FAST 1 (b)
6 CALL_FUNCTION 0 6 CALL_NO_KW 0
8 POP_TOP 8 POP_TOP
10 RETURN_VALUE 10 RETURN_VALUE
>> 12 PUSH_EXC_INFO >> 12 PUSH_EXC_INFO
14 LOAD_FAST 1 (b) 14 LOAD_FAST 1 (b)
16 CALL_FUNCTION 0 16 CALL_NO_KW 0
18 POP_TOP 18 POP_TOP
20 RERAISE 0 20 RERAISE 0
>> 22 POP_EXCEPT_AND_RERAISE >> 22 POP_EXCEPT_AND_RERAISE
@ -407,13 +407,13 @@ dis_tryfinallyconst = """\
%3d 2 NOP %3d 2 NOP
%3d 4 LOAD_FAST 0 (b) %3d 4 LOAD_FAST 0 (b)
6 CALL_FUNCTION 0 6 CALL_NO_KW 0
8 POP_TOP 8 POP_TOP
10 LOAD_CONST 1 (1) 10 LOAD_CONST 1 (1)
12 RETURN_VALUE 12 RETURN_VALUE
14 PUSH_EXC_INFO 14 PUSH_EXC_INFO
16 LOAD_FAST 0 (b) 16 LOAD_FAST 0 (b)
18 CALL_FUNCTION 0 18 CALL_NO_KW 0
20 POP_TOP 20 POP_TOP
22 RERAISE 0 22 RERAISE 0
>> 24 POP_EXCEPT_AND_RERAISE >> 24 POP_EXCEPT_AND_RERAISE
@ -468,7 +468,7 @@ Disassembly of <code object foo at 0x..., file "%s", line %d>:
10 MAKE_FUNCTION 8 (closure) 10 MAKE_FUNCTION 8 (closure)
12 LOAD_DEREF 1 (y) 12 LOAD_DEREF 1 (y)
14 GET_ITER 14 GET_ITER
16 CALL_FUNCTION 1 16 CALL_NO_KW 1
18 RETURN_VALUE 18 RETURN_VALUE
""" % (dis_nested_0, """ % (dis_nested_0,
__file__, __file__,
@ -1004,7 +1004,7 @@ expected_opinfo_outer = [
Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BUILD_LIST', opcode=103, arg=0, argval=0, argrepr='', offset=28, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='BUILD_MAP', opcode=105, arg=0, argval=0, argrepr='', offset=30, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Hello world!', argrepr="'Hello world!'", offset=32, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=6, argval='Hello world!', argrepr="'Hello world!'", offset=32, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=7, argval=7, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=7, argval=7, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=38, starts_line=8, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='f', argrepr='f', offset=38, starts_line=8, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
@ -1028,7 +1028,7 @@ expected_opinfo_f = [
Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=28, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=4, argval='b', argrepr='b', offset=28, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=30, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=0, argval='c', argrepr='c', offset=30, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=32, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=1, argval='d', argrepr='d', offset=32, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=4, argval=4, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=4, argval=4, argrepr='', offset=34, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=36, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=38, starts_line=6, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=2, argval='inner', argrepr='inner', offset=38, starts_line=6, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=40, starts_line=None, is_jump_target=False, positions=None),
@ -1043,7 +1043,7 @@ expected_opinfo_inner = [
Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=10, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_DEREF', opcode=137, arg=5, argval='d', argrepr='d', offset=10, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=12, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='e', argrepr='e', offset=12, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=14, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=1, argval='f', argrepr='f', offset=14, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=6, argval=6, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=6, argval=6, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=20, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=20, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=22, starts_line=None, is_jump_target=False, positions=None),
@ -1052,13 +1052,13 @@ expected_opinfo_inner = [
expected_opinfo_jumpy = [ expected_opinfo_jumpy = [
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=0, starts_line=3, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=0, argval='range', argrepr='range', offset=0, starts_line=3, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=2, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=1, argval=10, argrepr='10', offset=2, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=4, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=4, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=6, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='GET_ITER', opcode=68, arg=None, argval=None, argrepr='', offset=6, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='FOR_ITER', opcode=93, arg=17, argval=44, argrepr='to 44', offset=8, starts_line=None, is_jump_target=True, positions=None), Instruction(opname='FOR_ITER', opcode=93, arg=17, argval=44, argrepr='to 44', offset=8, starts_line=None, is_jump_target=True, positions=None),
Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=10, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=0, argval='i', argrepr='i', offset=10, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=12, starts_line=4, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=12, starts_line=4, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=14, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=14, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=16, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=18, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=20, starts_line=5, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=20, starts_line=5, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=22, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=2, argval=4, argrepr='4', offset=22, starts_line=None, is_jump_target=False, positions=None),
@ -1074,13 +1074,13 @@ expected_opinfo_jumpy = [
Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=4, argval=8, argrepr='to 8', offset=42, starts_line=7, is_jump_target=True, positions=None), Instruction(opname='JUMP_ABSOLUTE', opcode=113, arg=4, argval=8, argrepr='to 8', offset=42, starts_line=7, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=44, starts_line=10, is_jump_target=True, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=44, starts_line=10, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=4, argval='I can haz else clause?', argrepr="'I can haz else clause?'", offset=46, 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=46, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=48, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=48, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=50, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=52, starts_line=11, is_jump_target=True, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=52, starts_line=11, is_jump_target=True, positions=None),
Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=48, argval=96, argrepr='to 96', offset=54, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_FALSE', opcode=114, arg=48, argval=96, argrepr='to 96', offset=54, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=56, starts_line=12, is_jump_target=True, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=56, starts_line=12, is_jump_target=True, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=58, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=58, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=60, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=62, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=64, starts_line=13, is_jump_target=False, positions=None), Instruction(opname='LOAD_FAST', opcode=124, arg=0, argval='i', argrepr='i', offset=64, starts_line=13, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=66, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=66, starts_line=None, is_jump_target=False, positions=None),
@ -1100,7 +1100,7 @@ expected_opinfo_jumpy = [
Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=28, argval=56, argrepr='to 56', offset=94, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_JUMP_IF_TRUE', opcode=115, arg=28, argval=56, argrepr='to 56', offset=94, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=96, starts_line=19, is_jump_target=True, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=96, starts_line=19, is_jump_target=True, 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=98, 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=98, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=100, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=100, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=102, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=102, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=104, starts_line=20, is_jump_target=True, positions=None), Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=104, starts_line=20, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=106, starts_line=21, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=5, argval=1, argrepr='1', offset=106, starts_line=21, is_jump_target=False, positions=None),
@ -1116,7 +1116,7 @@ expected_opinfo_jumpy = [
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=126, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=128, starts_line=23, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=128, starts_line=23, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=130, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=8, argval='Here we go, here we go, here we go...', argrepr="'Here we go, here we go, here we go...'", offset=130, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=132, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=132, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=134, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT', opcode=89, arg=None, argval=None, argrepr='', offset=136, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=32, argval=204, argrepr='to 204', offset=138, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=32, argval=204, argrepr='to 204', offset=138, starts_line=None, is_jump_target=False, positions=None),
@ -1127,12 +1127,12 @@ expected_opinfo_jumpy = [
Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=148, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='STORE_FAST', opcode=125, arg=1, argval='dodgy', argrepr='dodgy', offset=148, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=150, starts_line=26, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=150, starts_line=26, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=152, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=9, argval='Never reach this', argrepr="'Never reach this'", offset=152, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=154, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=154, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', 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=25, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=158, starts_line=25, is_jump_target=False, positions=None),
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=160, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=162, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=3, argval=3, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=192, argrepr='to 192', offset=168, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='JUMP_FORWARD', opcode=110, arg=11, argval=192, argrepr='to 192', offset=168, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=170, starts_line=None, is_jump_target=False, positions=None),
@ -1148,21 +1148,21 @@ expected_opinfo_jumpy = [
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=190, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=192, starts_line=28, is_jump_target=True, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=192, starts_line=28, is_jump_target=True, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=10, argval="OK, now we're done", argrepr='"OK, now we\'re done"', offset=194, 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=194, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=196, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=196, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=198, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=198, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=200, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=200, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=202, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=204, starts_line=23, is_jump_target=True, positions=None), Instruction(opname='NOP', opcode=9, arg=None, argval=None, argrepr='', offset=204, starts_line=23, is_jump_target=True, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=206, starts_line=28, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=206, starts_line=28, 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=208, 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=208, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=210, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=212, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=214, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=214, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RETURN_VALUE', opcode=83, arg=None, argval=None, argrepr='', offset=216, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='PUSH_EXC_INFO', opcode=35, arg=None, argval=None, argrepr='', offset=218, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=220, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='LOAD_GLOBAL', opcode=116, arg=1, argval='print', argrepr='print', offset=220, 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=222, 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=222, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='CALL_FUNCTION', opcode=131, arg=1, argval=1, argrepr='', offset=224, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=224, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=226, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=226, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='RERAISE', opcode=119, arg=0, argval=0, argrepr='', offset=228, starts_line=None, is_jump_target=False, positions=None),
Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None), Instruction(opname='POP_EXCEPT_AND_RERAISE', opcode=37, arg=None, argval=None, argrepr='', offset=230, starts_line=None, is_jump_target=False, positions=None),

View File

@ -0,0 +1,8 @@
Replace the four call bytecode instructions which one pre-call instruction
and two call instructions.
Removes ``CALL_FUNCTION``, ``CALL_FUNCTION_KW``, ``CALL_METHOD`` and
``CALL_METHOD_KW``.
Adds ``CALL_NO_KW`` and ``CALL_KW`` call instructions, and
``PRECALL_METHOD`` prefix for pairing with ``LOAD_METHOD``.

View File

@ -23,7 +23,7 @@ compiles as follows in 3.10:
3 2 LOAD_GLOBAL 0 (g) 3 2 LOAD_GLOBAL 0 (g)
4 LOAD_CONST 1 (0) 4 LOAD_CONST 1 (0)
6 CALL_FUNCTION 1 6 CALL_NO_KW 1
8 POP_TOP 8 POP_TOP
10 POP_BLOCK 10 POP_BLOCK
12 LOAD_CONST 0 (None) 12 LOAD_CONST 0 (None)
@ -47,7 +47,7 @@ a table to determine where to jump to when an exception is raised.
3 2 LOAD_GLOBAL 0 (g) 3 2 LOAD_GLOBAL 0 (g)
4 LOAD_CONST 1 (0) 4 LOAD_CONST 1 (0)
6 CALL_FUNCTION 1 6 CALL_NO_KW 1
8 POP_TOP 8 POP_TOP
10 LOAD_CONST 0 (None) 10 LOAD_CONST 0 (None)
12 RETURN_VALUE 12 RETURN_VALUE
@ -68,7 +68,7 @@ ExceptionTable:
(Note this code is from an early 3.11 alpha, the NOP may well have be removed before release). (Note this code is from an early 3.11 alpha, the NOP may well have be removed before release).
If an instruction raises an exception then its offset is used to find the target to jump to. If an instruction raises an exception then its offset is used to find the target to jump to.
For example, the CALL_FUNCTION at offset 6, falls into the range 2 to 8. For example, the CALL_NO_KW at offset 6, falls into the range 2 to 8.
So, if g() raises an exception, then control jumps to offset 14. So, if g() raises an exception, then control jumps to offset 14.

View File

@ -188,7 +188,7 @@ which compiles to this:
3 6 LOAD_GLOBAL 0 (print) 3 6 LOAD_GLOBAL 0 (print)
8 LOAD_CONST 1 (1) 8 LOAD_CONST 1 (1)
10 CALL_FUNCTION 1 10 CALL_NO_KW 1
12 POP_TOP 12 POP_TOP
4 14 BREAK_LOOP 4 14 BREAK_LOOP
@ -197,7 +197,7 @@ which compiles to this:
6 20 LOAD_GLOBAL 0 (print) 6 20 LOAD_GLOBAL 0 (print)
22 LOAD_CONST 2 (2) 22 LOAD_CONST 2 (2)
24 CALL_FUNCTION 1 24 CALL_NO_KW 1
26 POP_TOP 26 POP_TOP
>> 28 LOAD_CONST 0 (None) >> 28 LOAD_CONST 0 (None)
30 RETURN_VALUE 30 RETURN_VALUE

View File

@ -2,11 +2,11 @@
unsigned char M_test_frozenmain[] = { unsigned char M_test_frozenmain[] = {
227,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, 227,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,
0,0,0,0,0,115,86,0,0,0,100,0,100,1,108,0, 0,0,0,0,0,115,86,0,0,0,100,0,100,1,108,0,
90,0,100,0,100,1,108,1,90,1,101,2,100,2,131,1, 90,0,100,0,100,1,108,1,90,1,101,2,100,2,169,1,
1,0,101,2,100,3,101,0,106,3,131,2,1,0,101,1, 1,0,101,2,100,3,101,0,106,3,169,2,1,0,101,1,
106,4,131,0,100,4,25,0,90,5,100,5,68,0,93,14, 106,4,169,0,100,4,25,0,90,5,100,5,68,0,93,14,
90,6,101,2,100,6,101,6,155,0,100,7,101,5,101,6, 90,6,101,2,100,6,101,6,155,0,100,7,101,5,101,6,
25,0,155,0,157,4,131,1,1,0,113,26,100,1,83,0, 25,0,155,0,157,4,169,1,1,0,113,26,100,1,83,0,
41,8,233,0,0,0,0,78,122,18,70,114,111,122,101,110, 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, 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,41,5, 115,46,97,114,103,118,218,6,99,111,110,102,105,103,41,5,

View File

@ -1673,6 +1673,22 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
CFrame cframe; CFrame cframe;
/* Variables used for making calls */
PyObject *kwnames;
int nargs;
/*
* It is only between a PRECALL_METHOD instruction and the following instruction,
* that these two values can be anything other than their defaults. */
int postcall_shrink = 1;
int extra_args = 0;
#define RESET_STACK_ADJUST_FOR_CALLS \
do { \
postcall_shrink = 1; \
extra_args = 0; \
} while (0)
#define STACK_ADJUST_IS_RESET \
(postcall_shrink == 1 && extra_args == 0)
/* WARNING: Because the CFrame lives on the C stack, /* WARNING: Because the CFrame lives on the C stack,
* but can be accessed from a heap allocated object (tstate) * but can be accessed from a heap allocated object (tstate)
* strict stack discipline must be maintained. * strict stack discipline must be maintained.
@ -1815,11 +1831,6 @@ check_eval_breaker:
switch (opcode) { switch (opcode) {
#endif #endif
/* Variables used for making calls */
PyObject *kwnames;
int nargs;
int postcall_shrink;
/* BEWARE! /* BEWARE!
It is essential that any operation that fails must goto error It is essential that any operation that fails must goto error
and that all operation that succeed call DISPATCH() ! */ and that all operation that succeed call DISPATCH() ! */
@ -4319,7 +4330,7 @@ check_eval_breaker:
if (iter == NULL) if (iter == NULL)
goto error; goto error;
PREDICT(FOR_ITER); PREDICT(FOR_ITER);
PREDICT(CALL_FUNCTION); PREDICT(CALL_NO_KW);
DISPATCH(); DISPATCH();
} }
@ -4661,7 +4672,7 @@ check_eval_breaker:
DISPATCH(); DISPATCH();
} }
TARGET(CALL_METHOD) { TARGET(PRECALL_METHOD) {
/* Designed to work in tamdem with LOAD_METHOD. */ /* Designed to work in tamdem with LOAD_METHOD. */
/* `meth` is NULL when LOAD_METHOD thinks that it's not /* `meth` is NULL when LOAD_METHOD thinks that it's not
a method call. a method call.
@ -4689,38 +4700,26 @@ check_eval_breaker:
make it accept the `self` as a first argument. make it accept the `self` as a first argument.
*/ */
int is_method = (PEEK(oparg + 2) != NULL); int is_method = (PEEK(oparg + 2) != NULL);
oparg += is_method; extra_args = is_method;
nargs = oparg;
kwnames = NULL;
postcall_shrink = 2-is_method; postcall_shrink = 2-is_method;
goto call_function; DISPATCH();
} }
TARGET(CALL_METHOD_KW) { TARGET(CALL_KW) {
/* Designed to work in tandem with LOAD_METHOD. Same as CALL_METHOD
but pops TOS to get a tuple of keyword names. */
kwnames = POP(); kwnames = POP();
int is_method = (PEEK(oparg + 2) != NULL); oparg += extra_args;
oparg += is_method; extra_args = 0;
nargs = oparg - (int)PyTuple_GET_SIZE(kwnames); nargs = oparg - (int)PyTuple_GET_SIZE(kwnames);
postcall_shrink = 2-is_method;
goto call_function; goto call_function;
} }
TARGET(CALL_FUNCTION_KW) { TARGET(CALL_NO_KW) {
kwnames = POP();
nargs = oparg - (int)PyTuple_GET_SIZE(kwnames);
postcall_shrink = 1;
goto call_function;
}
TARGET(CALL_FUNCTION) {
PREDICTED(CALL_FUNCTION);
STAT_INC(CALL_FUNCTION, unquickened);
PyObject *function; PyObject *function;
nargs = oparg; PREDICTED(CALL_NO_KW);
STAT_INC(CALL_NO_KW, unquickened);
kwnames = NULL; kwnames = NULL;
postcall_shrink = 1; oparg += extra_args;
nargs = oparg;
call_function: call_function:
function = PEEK(oparg + 1); function = PEEK(oparg + 1);
if (Py_TYPE(function) == &PyMethod_Type) { if (Py_TYPE(function) == &PyMethod_Type) {
@ -4748,6 +4747,7 @@ check_eval_breaker:
stack_pointer, nargs, kwnames stack_pointer, nargs, kwnames
); );
STACK_SHRINK(postcall_shrink); STACK_SHRINK(postcall_shrink);
RESET_STACK_ADJUST_FOR_CALLS;
// The frame has stolen all the arguments from the stack, // The frame has stolen all the arguments from the stack,
// so there is no need to clean them up. // so there is no need to clean them up.
Py_XDECREF(kwnames); Py_XDECREF(kwnames);
@ -4780,6 +4780,7 @@ check_eval_breaker:
Py_DECREF(stack_pointer[i]); Py_DECREF(stack_pointer[i]);
} }
STACK_SHRINK(postcall_shrink); STACK_SHRINK(postcall_shrink);
RESET_STACK_ADJUST_FOR_CALLS;
PUSH(res); PUSH(res);
if (res == NULL) { if (res == NULL) {
goto error; goto error;
@ -4788,43 +4789,46 @@ check_eval_breaker:
DISPATCH(); DISPATCH();
} }
TARGET(CALL_FUNCTION_ADAPTIVE) { TARGET(CALL_NO_KW_ADAPTIVE) {
SpecializedCacheEntry *cache = GET_CACHE(); SpecializedCacheEntry *cache = GET_CACHE();
nargs = cache->adaptive.original_oparg; oparg = cache->adaptive.original_oparg;
if (cache->adaptive.counter == 0) { if (cache->adaptive.counter == 0) {
next_instr--; next_instr--;
if (_Py_Specialize_CallFunction( int nargs = oparg+extra_args;
if (_Py_Specialize_CallNoKw(
PEEK(nargs + 1), next_instr, nargs, cache, BUILTINS()) < 0) { PEEK(nargs + 1), next_instr, nargs, cache, BUILTINS()) < 0) {
goto error; goto error;
} }
DISPATCH(); DISPATCH();
} }
else { else {
STAT_INC(CALL_FUNCTION, deferred); STAT_INC(CALL_NO_KW, deferred);
cache->adaptive.counter--; cache->adaptive.counter--;
oparg = nargs;
kwnames = NULL; kwnames = NULL;
postcall_shrink = 1; oparg += extra_args;
nargs = oparg;
goto call_function; goto call_function;
} }
} }
TARGET(CALL_FUNCTION_PY_SIMPLE) { TARGET(CALL_NO_KW_PY_SIMPLE) {
SpecializedCacheEntry *caches = GET_CACHE(); SpecializedCacheEntry *caches = GET_CACHE();
_PyAdaptiveEntry *cache0 = &caches[0].adaptive; _PyAdaptiveEntry *cache0 = &caches[0].adaptive;
int argcount = cache0->original_oparg; int argcount = cache0->original_oparg + extra_args;
DEOPT_IF(argcount != cache0->index, CALL_NO_KW);
_PyCallCache *cache1 = &caches[-1].call; _PyCallCache *cache1 = &caches[-1].call;
PyObject *callable = PEEK(argcount+1); PyObject *callable = PEEK(argcount+1);
DEOPT_IF(!PyFunction_Check(callable), CALL_FUNCTION); DEOPT_IF(!PyFunction_Check(callable), CALL_NO_KW);
PyFunctionObject *func = (PyFunctionObject *)callable; PyFunctionObject *func = (PyFunctionObject *)callable;
DEOPT_IF(func->func_version != cache1->func_version, CALL_FUNCTION); DEOPT_IF(func->func_version != cache1->func_version, CALL_NO_KW);
/* PEP 523 */ /* PEP 523 */
DEOPT_IF(tstate->interp->eval_frame != NULL, CALL_FUNCTION); DEOPT_IF(tstate->interp->eval_frame != NULL, CALL_NO_KW);
STAT_INC(CALL_FUNCTION, hit); STAT_INC(CALL_NO_KW, hit);
PyCodeObject *code = (PyCodeObject *)func->func_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE; size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
InterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size); InterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size);
if (new_frame == NULL) { if (new_frame == NULL) {
RESET_STACK_ADJUST_FOR_CALLS;
goto error; goto error;
} }
_PyFrame_InitializeSpecials(new_frame, func, _PyFrame_InitializeSpecials(new_frame, func,
@ -4842,7 +4846,8 @@ check_eval_breaker:
for (int i = argcount+deflen; i < code->co_nlocalsplus; i++) { for (int i = argcount+deflen; i < code->co_nlocalsplus; i++) {
new_frame->localsplus[i] = NULL; new_frame->localsplus[i] = NULL;
} }
STACK_SHRINK(1); STACK_SHRINK(postcall_shrink);
RESET_STACK_ADJUST_FOR_CALLS;
Py_DECREF(func); Py_DECREF(func);
_PyFrame_SetStackPointer(frame, stack_pointer); _PyFrame_SetStackPointer(frame, stack_pointer);
new_frame->previous = frame; new_frame->previous = frame;
@ -4851,14 +4856,15 @@ check_eval_breaker:
goto start_frame; goto start_frame;
} }
TARGET(CALL_FUNCTION_BUILTIN_O) { TARGET(CALL_NO_KW_BUILTIN_O) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(STACK_ADJUST_IS_RESET);
/* Builtin METH_O functions */ /* Builtin METH_O functions */
PyObject *callable = SECOND(); PyObject *callable = SECOND();
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL_FUNCTION); DEOPT_IF(!PyCFunction_CheckExact(callable), CALL_NO_KW);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL_FUNCTION); DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL_NO_KW);
STAT_INC(CALL_FUNCTION, hit); STAT_INC(CALL_NO_KW, hit);
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
// This is slower but CPython promises to check all non-vectorcall // This is slower but CPython promises to check all non-vectorcall
@ -4881,18 +4887,19 @@ check_eval_breaker:
DISPATCH(); DISPATCH();
} }
TARGET(CALL_FUNCTION_BUILTIN_FAST) { TARGET(CALL_NO_KW_BUILTIN_FAST) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(STACK_ADJUST_IS_RESET);
/* Builtin METH_FASTCALL functions, without keywords */ /* Builtin METH_FASTCALL functions, without keywords */
SpecializedCacheEntry *caches = GET_CACHE(); SpecializedCacheEntry *caches = GET_CACHE();
_PyAdaptiveEntry *cache0 = &caches[0].adaptive; _PyAdaptiveEntry *cache0 = &caches[0].adaptive;
int nargs = cache0->original_oparg; int nargs = cache0->original_oparg;
PyObject **pfunc = &PEEK(nargs + 1); PyObject **pfunc = &PEEK(nargs + 1);
PyObject *callable = *pfunc; PyObject *callable = *pfunc;
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL_FUNCTION); DEOPT_IF(!PyCFunction_CheckExact(callable), CALL_NO_KW);
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL,
CALL_FUNCTION); CALL_NO_KW);
STAT_INC(CALL_FUNCTION, hit); STAT_INC(CALL_NO_KW, hit);
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable); PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
/* res = func(self, args, nargs) */ /* res = func(self, args, nargs) */
@ -4919,16 +4926,17 @@ check_eval_breaker:
DISPATCH(); DISPATCH();
} }
TARGET(CALL_FUNCTION_LEN) { TARGET(CALL_NO_KW_LEN) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(STACK_ADJUST_IS_RESET);
/* len(o) */ /* len(o) */
SpecializedCacheEntry *caches = GET_CACHE(); SpecializedCacheEntry *caches = GET_CACHE();
assert(caches[0].adaptive.original_oparg == 1); assert(caches[0].adaptive.original_oparg == 1);
_PyObjectCache *cache1 = &caches[-1].obj; _PyObjectCache *cache1 = &caches[-1].obj;
PyObject *callable = SECOND(); PyObject *callable = SECOND();
DEOPT_IF(callable != cache1->obj, CALL_FUNCTION); DEOPT_IF(callable != cache1->obj, CALL_NO_KW);
STAT_INC(CALL_FUNCTION, hit); STAT_INC(CALL_NO_KW, hit);
Py_ssize_t len_i = PyObject_Length(TOP()); Py_ssize_t len_i = PyObject_Length(TOP());
if (len_i < 0) { if (len_i < 0) {
@ -4947,16 +4955,17 @@ check_eval_breaker:
DISPATCH(); DISPATCH();
} }
TARGET(CALL_FUNCTION_ISINSTANCE) { TARGET(CALL_NO_KW_ISINSTANCE) {
assert(cframe.use_tracing == 0); assert(cframe.use_tracing == 0);
assert(STACK_ADJUST_IS_RESET);
/* isinstance(o, o2) */ /* isinstance(o, o2) */
SpecializedCacheEntry *caches = GET_CACHE(); SpecializedCacheEntry *caches = GET_CACHE();
assert(caches[0].adaptive.original_oparg == 2); assert(caches[0].adaptive.original_oparg == 2);
_PyObjectCache *cache1 = &caches[-1].obj; _PyObjectCache *cache1 = &caches[-1].obj;
PyObject *callable = THIRD(); PyObject *callable = THIRD();
DEOPT_IF(callable != cache1->obj, CALL_FUNCTION); DEOPT_IF(callable != cache1->obj, CALL_NO_KW);
STAT_INC(CALL_FUNCTION, hit); STAT_INC(CALL_NO_KW, hit);
int retval = PyObject_IsInstance(SECOND(), TOP()); int retval = PyObject_IsInstance(SECOND(), TOP());
if (retval < 0) { if (retval < 0) {
@ -4976,6 +4985,97 @@ check_eval_breaker:
DISPATCH(); DISPATCH();
} }
TARGET(CALL_NO_KW_LIST_APPEND) {
assert(_Py_OPCODE(next_instr[-2]) == PRECALL_METHOD);
assert(GET_CACHE()->adaptive.original_oparg == 1);
DEOPT_IF(extra_args == 0, CALL_NO_KW);
PyObject *list = SECOND();
DEOPT_IF(!PyList_CheckExact(list), CALL_NO_KW);
STAT_INC(CALL_NO_KW, hit);
assert(extra_args == 1);
extra_args = 0;
assert(STACK_ADJUST_IS_RESET);
PyObject *arg = TOP();
int err = PyList_Append(list, arg);
if (err) {
goto error;
}
PyObject *callable = THIRD();
Py_DECREF(arg);
Py_DECREF(list);
Py_INCREF(Py_None);
STACK_SHRINK(2);
SET_TOP(Py_None);
Py_DECREF(callable);
DISPATCH();
}
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) {
assert(_Py_OPCODE(next_instr[-2]) == PRECALL_METHOD);
assert(GET_CACHE()->adaptive.original_oparg == 1);
DEOPT_IF(extra_args == 0, CALL_NO_KW);
assert(extra_args == 1);
PyObject *callable = THIRD();
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL_NO_KW);
DEOPT_IF(((PyMethodDescrObject *)callable)->d_method->ml_flags != METH_O, CALL_NO_KW);
STAT_INC(CALL_NO_KW, hit);
assert(extra_args == 1);
extra_args = 0;
assert(STACK_ADJUST_IS_RESET);
PyCFunction cfunc = ((PyMethodDescrObject *)callable)->d_method->ml_meth;
// This is slower but CPython promises to check all non-vectorcall
// function calls.
if (_Py_EnterRecursiveCall(tstate, " while calling a Python object")) {
goto error;
}
PyObject *arg = POP();
PyObject *self = POP();
PyObject *res = cfunc(self, arg);
_Py_LeaveRecursiveCall(tstate);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
Py_DECREF(self);
Py_DECREF(arg);
SET_TOP(res);
Py_DECREF(callable);
if (res == NULL) {
goto error;
}
DISPATCH();
}
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) {
assert(_Py_OPCODE(next_instr[-2]) == PRECALL_METHOD);
/* Builtin METH_FASTCALL methods, without keywords */
SpecializedCacheEntry *caches = GET_CACHE();
_PyAdaptiveEntry *cache0 = &caches[0].adaptive;
DEOPT_IF(extra_args == 0, CALL_NO_KW);
assert(extra_args == 1);
int nargs = cache0->original_oparg;
PyObject *callable = PEEK(nargs + 2);
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL_NO_KW);
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL_NO_KW);
STAT_INC(CALL_NO_KW, hit);
assert(extra_args == 1);
extra_args = 0;
assert(STACK_ADJUST_IS_RESET);
_PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth;
PyObject *self = PEEK(nargs+1);
PyObject *res = cfunc(self, &PEEK(nargs), nargs);
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
/* Clear the stack of the arguments. */
STACK_SHRINK(nargs+1);
for (int i = 0; i <= nargs; i++) {
Py_DECREF(stack_pointer[i]);
}
SET_TOP(res);
Py_DECREF(callable);
if (res == NULL) {
goto error;
}
DISPATCH();
}
TARGET(CALL_FUNCTION_EX) { TARGET(CALL_FUNCTION_EX) {
PREDICTED(CALL_FUNCTION_EX); PREDICTED(CALL_FUNCTION_EX);
PyObject *func, *callargs, *kwargs = NULL, *result; PyObject *func, *callargs, *kwargs = NULL, *result;
@ -5289,7 +5389,7 @@ MISS_WITH_CACHE(LOAD_ATTR)
MISS_WITH_CACHE(STORE_ATTR) MISS_WITH_CACHE(STORE_ATTR)
MISS_WITH_CACHE(LOAD_GLOBAL) MISS_WITH_CACHE(LOAD_GLOBAL)
MISS_WITH_CACHE(LOAD_METHOD) MISS_WITH_CACHE(LOAD_METHOD)
MISS_WITH_CACHE(CALL_FUNCTION) MISS_WITH_CACHE(CALL_NO_KW)
MISS_WITH_CACHE(BINARY_OP) MISS_WITH_CACHE(BINARY_OP)
MISS_WITH_CACHE(COMPARE_OP) MISS_WITH_CACHE(COMPARE_OP)
MISS_WITH_CACHE(BINARY_SUBSCR) MISS_WITH_CACHE(BINARY_SUBSCR)
@ -7509,7 +7609,7 @@ format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int prevprevop
"that does not implement __await__: %.100s", "that does not implement __await__: %.100s",
type->tp_name); type->tp_name);
} }
else if (prevopcode == WITH_EXCEPT_START || (prevopcode == CALL_FUNCTION && prevprevopcode == DUP_TOP)) { else if (prevopcode == WITH_EXCEPT_START || (prevopcode == CALL_NO_KW && prevprevopcode == DUP_TOP)) {
_PyErr_Format(tstate, PyExc_TypeError, _PyErr_Format(tstate, PyExc_TypeError,
"'async with' received an object from __aexit__ " "'async with' received an object from __aexit__ "
"that does not implement __await__: %.100s", "that does not implement __await__: %.100s",

View File

@ -1155,13 +1155,11 @@ stack_effect(int opcode, int oparg, int jump)
return -oparg; return -oparg;
/* Functions and calls */ /* Functions and calls */
case CALL_FUNCTION: case PRECALL_METHOD:
return -1;
case CALL_NO_KW:
return -oparg; return -oparg;
case CALL_METHOD: case CALL_KW:
return -oparg-1;
case CALL_METHOD_KW:
return -oparg-2;
case CALL_FUNCTION_KW:
return -oparg-1; return -oparg-1;
case CALL_FUNCTION_EX: case CALL_FUNCTION_EX:
return -1 - ((oparg & 0x01) != 0); return -1 - ((oparg & 0x01) != 0);
@ -1817,7 +1815,7 @@ compiler_call_exit_with_nones(struct compiler *c) {
ADDOP_LOAD_CONST(c, Py_None); ADDOP_LOAD_CONST(c, Py_None);
ADDOP(c, DUP_TOP); ADDOP(c, DUP_TOP);
ADDOP(c, DUP_TOP); ADDOP(c, DUP_TOP);
ADDOP_I(c, CALL_FUNCTION, 3); ADDOP_I(c, CALL_NO_KW, 3);
return 1; return 1;
} }
@ -2166,7 +2164,7 @@ compiler_apply_decorators(struct compiler *c, asdl_expr_seq* decos)
int old_end_col_offset = c->u->u_end_col_offset; int old_end_col_offset = c->u->u_end_col_offset;
for (Py_ssize_t i = asdl_seq_LEN(decos) - 1; i > -1; i--) { for (Py_ssize_t i = asdl_seq_LEN(decos) - 1; i > -1; i--) {
SET_LOC(c, (expr_ty)asdl_seq_GET(decos, i)); SET_LOC(c, (expr_ty)asdl_seq_GET(decos, i));
ADDOP_I(c, CALL_FUNCTION, 1); ADDOP_I(c, CALL_NO_KW, 1);
} }
c->u->u_lineno = old_lineno; c->u->u_lineno = old_lineno;
c->u->u_end_lineno = old_end_lineno; c->u->u_end_lineno = old_end_lineno;
@ -3885,7 +3883,7 @@ compiler_assert(struct compiler *c, stmt_ty s)
ADDOP(c, LOAD_ASSERTION_ERROR); ADDOP(c, LOAD_ASSERTION_ERROR);
if (s->v.Assert.msg) { if (s->v.Assert.msg) {
VISIT(c, expr, s->v.Assert.msg); VISIT(c, expr, s->v.Assert.msg);
ADDOP_I(c, CALL_FUNCTION, 1); ADDOP_I(c, CALL_NO_KW, 1);
} }
ADDOP_I(c, RAISE_VARARGS, 1); ADDOP_I(c, RAISE_VARARGS, 1);
compiler_use_next_block(c, end); compiler_use_next_block(c, end);
@ -4693,10 +4691,12 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
if (!compiler_call_simple_kw_helper(c, kwds, kwdsl)) { if (!compiler_call_simple_kw_helper(c, kwds, kwdsl)) {
return 0; return 0;
}; };
ADDOP_I(c, CALL_METHOD_KW, argsl + kwdsl); ADDOP_I(c, PRECALL_METHOD, argsl + kwdsl+1);
ADDOP_I(c, CALL_KW, argsl + kwdsl);
} }
else { else {
ADDOP_I(c, CALL_METHOD, argsl); ADDOP_I(c, PRECALL_METHOD, argsl);
ADDOP_I(c, CALL_NO_KW, argsl);
} }
c->u->u_lineno = old_lineno; c->u->u_lineno = old_lineno;
return 1; return 1;
@ -4763,7 +4763,8 @@ compiler_joined_str(struct compiler *c, expr_ty e)
VISIT(c, expr, asdl_seq_GET(e->v.JoinedStr.values, i)); VISIT(c, expr, asdl_seq_GET(e->v.JoinedStr.values, i));
ADDOP_I(c, LIST_APPEND, 1); ADDOP_I(c, LIST_APPEND, 1);
} }
ADDOP_I(c, CALL_METHOD, 1); ADDOP_I(c, PRECALL_METHOD, 1);
ADDOP_I(c, CALL_NO_KW, 1);
} }
else { else {
VISIT_SEQ(c, expr, e->v.JoinedStr.values); VISIT_SEQ(c, expr, e->v.JoinedStr.values);
@ -4935,11 +4936,11 @@ compiler_call_helper(struct compiler *c,
if (!compiler_call_simple_kw_helper(c, keywords, nkwelts)) { if (!compiler_call_simple_kw_helper(c, keywords, nkwelts)) {
return 0; return 0;
}; };
ADDOP_I(c, CALL_FUNCTION_KW, n + nelts + nkwelts); ADDOP_I(c, CALL_KW, n + nelts + nkwelts);
return 1; return 1;
} }
else { else {
ADDOP_I(c, CALL_FUNCTION, n + nelts); ADDOP_I(c, CALL_NO_KW, n + nelts);
return 1; return 1;
} }
@ -5336,7 +5337,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
ADDOP(c, GET_ITER); ADDOP(c, GET_ITER);
} }
ADDOP_I(c, CALL_FUNCTION, 1); ADDOP_I(c, CALL_NO_KW, 1);
if (is_async_generator && type != COMP_GENEXP) { if (is_async_generator && type != COMP_GENEXP) {
ADDOP(c, GET_AWAITABLE); ADDOP(c, GET_AWAITABLE);

View File

@ -39,34 +39,34 @@ static void *opcode_targets[256] = {
&&TARGET_POP_EXCEPT_AND_RERAISE, &&TARGET_POP_EXCEPT_AND_RERAISE,
&&TARGET_STORE_SUBSCR_LIST_INT, &&TARGET_STORE_SUBSCR_LIST_INT,
&&TARGET_STORE_SUBSCR_DICT, &&TARGET_STORE_SUBSCR_DICT,
&&TARGET_CALL_FUNCTION_ADAPTIVE, &&TARGET_CALL_NO_KW_ADAPTIVE,
&&TARGET_CALL_FUNCTION_BUILTIN_O, &&TARGET_CALL_NO_KW_BUILTIN_O,
&&TARGET_CALL_FUNCTION_BUILTIN_FAST, &&TARGET_CALL_NO_KW_BUILTIN_FAST,
&&TARGET_CALL_FUNCTION_LEN, &&TARGET_CALL_NO_KW_LEN,
&&TARGET_CALL_FUNCTION_ISINSTANCE, &&TARGET_CALL_NO_KW_ISINSTANCE,
&&TARGET_CALL_FUNCTION_PY_SIMPLE, &&TARGET_CALL_NO_KW_PY_SIMPLE,
&&TARGET_JUMP_ABSOLUTE_QUICK, &&TARGET_CALL_NO_KW_LIST_APPEND,
&&TARGET_LOAD_ATTR_ADAPTIVE, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O,
&&TARGET_LOAD_ATTR_INSTANCE_VALUE, &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST,
&&TARGET_WITH_EXCEPT_START, &&TARGET_WITH_EXCEPT_START,
&&TARGET_GET_AITER, &&TARGET_GET_AITER,
&&TARGET_GET_ANEXT, &&TARGET_GET_ANEXT,
&&TARGET_BEFORE_ASYNC_WITH, &&TARGET_BEFORE_ASYNC_WITH,
&&TARGET_BEFORE_WITH, &&TARGET_BEFORE_WITH,
&&TARGET_END_ASYNC_FOR, &&TARGET_END_ASYNC_FOR,
&&TARGET_JUMP_ABSOLUTE_QUICK,
&&TARGET_LOAD_ATTR_ADAPTIVE,
&&TARGET_LOAD_ATTR_INSTANCE_VALUE,
&&TARGET_LOAD_ATTR_WITH_HINT, &&TARGET_LOAD_ATTR_WITH_HINT,
&&TARGET_LOAD_ATTR_SLOT, &&TARGET_LOAD_ATTR_SLOT,
&&TARGET_STORE_SUBSCR,
&&TARGET_DELETE_SUBSCR,
&&TARGET_LOAD_ATTR_MODULE, &&TARGET_LOAD_ATTR_MODULE,
&&TARGET_LOAD_GLOBAL_ADAPTIVE, &&TARGET_LOAD_GLOBAL_ADAPTIVE,
&&TARGET_LOAD_GLOBAL_MODULE, &&TARGET_LOAD_GLOBAL_MODULE,
&&TARGET_STORE_SUBSCR,
&&TARGET_DELETE_SUBSCR,
&&TARGET_LOAD_GLOBAL_BUILTIN, &&TARGET_LOAD_GLOBAL_BUILTIN,
&&TARGET_LOAD_METHOD_ADAPTIVE, &&TARGET_LOAD_METHOD_ADAPTIVE,
&&TARGET_LOAD_METHOD_CACHED, &&TARGET_LOAD_METHOD_CACHED,
&&TARGET_LOAD_METHOD_CLASS,
&&TARGET_LOAD_METHOD_MODULE,
&&TARGET_LOAD_METHOD_NO_DICT,
&&TARGET_GET_ITER, &&TARGET_GET_ITER,
&&TARGET_GET_YIELD_FROM_ITER, &&TARGET_GET_YIELD_FROM_ITER,
&&TARGET_PRINT_EXPR, &&TARGET_PRINT_EXPR,
@ -74,19 +74,19 @@ static void *opcode_targets[256] = {
&&TARGET_YIELD_FROM, &&TARGET_YIELD_FROM,
&&TARGET_GET_AWAITABLE, &&TARGET_GET_AWAITABLE,
&&TARGET_LOAD_ASSERTION_ERROR, &&TARGET_LOAD_ASSERTION_ERROR,
&&TARGET_LOAD_METHOD_CLASS,
&&TARGET_LOAD_METHOD_MODULE,
&&TARGET_LOAD_METHOD_NO_DICT,
&&TARGET_STORE_ATTR_ADAPTIVE, &&TARGET_STORE_ATTR_ADAPTIVE,
&&TARGET_STORE_ATTR_INSTANCE_VALUE, &&TARGET_STORE_ATTR_INSTANCE_VALUE,
&&TARGET_STORE_ATTR_SLOT, &&TARGET_STORE_ATTR_SLOT,
&&TARGET_STORE_ATTR_WITH_HINT, &&TARGET_STORE_ATTR_WITH_HINT,
&&TARGET_LOAD_FAST__LOAD_FAST,
&&TARGET_STORE_FAST__LOAD_FAST,
&&TARGET_LOAD_FAST__LOAD_CONST,
&&TARGET_LIST_TO_TUPLE, &&TARGET_LIST_TO_TUPLE,
&&TARGET_RETURN_VALUE, &&TARGET_RETURN_VALUE,
&&TARGET_IMPORT_STAR, &&TARGET_IMPORT_STAR,
&&TARGET_SETUP_ANNOTATIONS, &&TARGET_SETUP_ANNOTATIONS,
&&TARGET_YIELD_VALUE, &&TARGET_YIELD_VALUE,
&&TARGET_LOAD_CONST__LOAD_FAST, &&TARGET_LOAD_FAST__LOAD_FAST,
&&TARGET_PREP_RERAISE_STAR, &&TARGET_PREP_RERAISE_STAR,
&&TARGET_POP_EXCEPT, &&TARGET_POP_EXCEPT,
&&TARGET_STORE_NAME, &&TARGET_STORE_NAME,
@ -122,25 +122,25 @@ static void *opcode_targets[256] = {
&&TARGET_COPY, &&TARGET_COPY,
&&TARGET_JUMP_IF_NOT_EXC_MATCH, &&TARGET_JUMP_IF_NOT_EXC_MATCH,
&&TARGET_BINARY_OP, &&TARGET_BINARY_OP,
&&TARGET_STORE_FAST__STORE_FAST, &&TARGET_STORE_FAST__LOAD_FAST,
&&TARGET_LOAD_FAST, &&TARGET_LOAD_FAST,
&&TARGET_STORE_FAST, &&TARGET_STORE_FAST,
&&TARGET_DELETE_FAST, &&TARGET_DELETE_FAST,
&&TARGET_JUMP_IF_NOT_EG_MATCH, &&TARGET_JUMP_IF_NOT_EG_MATCH,
&&_unknown_opcode, &&TARGET_LOAD_FAST__LOAD_CONST,
&&TARGET_GEN_START, &&TARGET_GEN_START,
&&TARGET_RAISE_VARARGS, &&TARGET_RAISE_VARARGS,
&&TARGET_CALL_FUNCTION, &&TARGET_LOAD_CONST__LOAD_FAST,
&&TARGET_MAKE_FUNCTION, &&TARGET_MAKE_FUNCTION,
&&TARGET_BUILD_SLICE, &&TARGET_BUILD_SLICE,
&&_unknown_opcode, &&TARGET_STORE_FAST__STORE_FAST,
&&TARGET_MAKE_CELL, &&TARGET_MAKE_CELL,
&&TARGET_LOAD_CLOSURE, &&TARGET_LOAD_CLOSURE,
&&TARGET_LOAD_DEREF, &&TARGET_LOAD_DEREF,
&&TARGET_STORE_DEREF, &&TARGET_STORE_DEREF,
&&TARGET_DELETE_DEREF, &&TARGET_DELETE_DEREF,
&&_unknown_opcode, &&_unknown_opcode,
&&TARGET_CALL_FUNCTION_KW, &&_unknown_opcode,
&&TARGET_CALL_FUNCTION_EX, &&TARGET_CALL_FUNCTION_EX,
&&_unknown_opcode, &&_unknown_opcode,
&&TARGET_EXTENDED_ARG, &&TARGET_EXTENDED_ARG,
@ -160,16 +160,16 @@ static void *opcode_targets[256] = {
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&TARGET_LOAD_METHOD, &&TARGET_LOAD_METHOD,
&&TARGET_CALL_METHOD, &&_unknown_opcode,
&&TARGET_LIST_EXTEND, &&TARGET_LIST_EXTEND,
&&TARGET_SET_UPDATE, &&TARGET_SET_UPDATE,
&&TARGET_DICT_MERGE, &&TARGET_DICT_MERGE,
&&TARGET_DICT_UPDATE, &&TARGET_DICT_UPDATE,
&&TARGET_CALL_METHOD_KW,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&TARGET_PRECALL_METHOD,
&&TARGET_CALL_NO_KW,
&&TARGET_CALL_KW,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,
&&_unknown_opcode, &&_unknown_opcode,

View File

@ -127,7 +127,7 @@ _Py_GetSpecializationStats(void) {
err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr"); err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr");
err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr"); err += add_stat_dict(stats, STORE_SUBSCR, "store_subscr");
err += add_stat_dict(stats, STORE_ATTR, "store_attr"); err += add_stat_dict(stats, STORE_ATTR, "store_attr");
err += add_stat_dict(stats, CALL_FUNCTION, "call_function"); err += add_stat_dict(stats, CALL_NO_KW, "call_no_kw");
err += add_stat_dict(stats, BINARY_OP, "binary_op"); err += add_stat_dict(stats, BINARY_OP, "binary_op");
err += add_stat_dict(stats, COMPARE_OP, "compare_op"); err += add_stat_dict(stats, COMPARE_OP, "compare_op");
if (err < 0) { if (err < 0) {
@ -186,7 +186,7 @@ _Py_PrintSpecializationStats(void)
print_stats(out, &_specialization_stats[BINARY_SUBSCR], "binary_subscr"); print_stats(out, &_specialization_stats[BINARY_SUBSCR], "binary_subscr");
print_stats(out, &_specialization_stats[STORE_SUBSCR], "store_subscr"); print_stats(out, &_specialization_stats[STORE_SUBSCR], "store_subscr");
print_stats(out, &_specialization_stats[STORE_ATTR], "store_attr"); print_stats(out, &_specialization_stats[STORE_ATTR], "store_attr");
print_stats(out, &_specialization_stats[CALL_FUNCTION], "call_function"); print_stats(out, &_specialization_stats[CALL_NO_KW], "call_no_kw");
print_stats(out, &_specialization_stats[BINARY_OP], "binary_op"); print_stats(out, &_specialization_stats[BINARY_OP], "binary_op");
print_stats(out, &_specialization_stats[COMPARE_OP], "compare_op"); print_stats(out, &_specialization_stats[COMPARE_OP], "compare_op");
if (out != stderr) { if (out != stderr) {
@ -238,7 +238,7 @@ static uint8_t adaptive_opcodes[256] = {
[LOAD_METHOD] = LOAD_METHOD_ADAPTIVE, [LOAD_METHOD] = LOAD_METHOD_ADAPTIVE,
[BINARY_SUBSCR] = BINARY_SUBSCR_ADAPTIVE, [BINARY_SUBSCR] = BINARY_SUBSCR_ADAPTIVE,
[STORE_SUBSCR] = STORE_SUBSCR_ADAPTIVE, [STORE_SUBSCR] = STORE_SUBSCR_ADAPTIVE,
[CALL_FUNCTION] = CALL_FUNCTION_ADAPTIVE, [CALL_NO_KW] = CALL_NO_KW_ADAPTIVE,
[STORE_ATTR] = STORE_ATTR_ADAPTIVE, [STORE_ATTR] = STORE_ATTR_ADAPTIVE,
[BINARY_OP] = BINARY_OP_ADAPTIVE, [BINARY_OP] = BINARY_OP_ADAPTIVE,
[COMPARE_OP] = COMPARE_OP_ADAPTIVE, [COMPARE_OP] = COMPARE_OP_ADAPTIVE,
@ -251,7 +251,7 @@ static uint8_t cache_requirements[256] = {
[LOAD_METHOD] = 3, /* _PyAdaptiveEntry, _PyAttrCache and _PyObjectCache */ [LOAD_METHOD] = 3, /* _PyAdaptiveEntry, _PyAttrCache and _PyObjectCache */
[BINARY_SUBSCR] = 2, /* _PyAdaptiveEntry, _PyObjectCache */ [BINARY_SUBSCR] = 2, /* _PyAdaptiveEntry, _PyObjectCache */
[STORE_SUBSCR] = 0, [STORE_SUBSCR] = 0,
[CALL_FUNCTION] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */ [CALL_NO_KW] = 2, /* _PyAdaptiveEntry and _PyObjectCache/_PyCallCache */
[STORE_ATTR] = 2, /* _PyAdaptiveEntry and _PyAttrCache */ [STORE_ATTR] = 2, /* _PyAdaptiveEntry and _PyAttrCache */
[BINARY_OP] = 1, // _PyAdaptiveEntry [BINARY_OP] = 1, // _PyAdaptiveEntry
[COMPARE_OP] = 1, /* _PyAdaptiveEntry */ [COMPARE_OP] = 1, /* _PyAdaptiveEntry */
@ -491,6 +491,8 @@ initial_counter_value(void) {
#define SPEC_FAIL_PYCFUNCTION_NOARGS 16 #define SPEC_FAIL_PYCFUNCTION_NOARGS 16
#define SPEC_FAIL_BAD_CALL_FLAGS 17 #define SPEC_FAIL_BAD_CALL_FLAGS 17
#define SPEC_FAIL_CLASS 18 #define SPEC_FAIL_CLASS 18
#define SPEC_FAIL_C_METHOD_CALL 19
#define SPEC_FAIL_METHDESCR_NON_METHOD 20
/* COMPARE_OP */ /* COMPARE_OP */
#define SPEC_FAIL_STRING_COMPARE 13 #define SPEC_FAIL_STRING_COMPARE 13
@ -1261,7 +1263,51 @@ specialize_class_call(
PyObject *callable, _Py_CODEUNIT *instr, PyObject *callable, _Py_CODEUNIT *instr,
int nargs, SpecializedCacheEntry *cache) int nargs, SpecializedCacheEntry *cache)
{ {
SPECIALIZATION_FAIL(CALL_FUNCTION, SPEC_FAIL_CLASS); SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_CLASS);
return -1;
}
static PyMethodDescrObject *_list_append = NULL;
_Py_IDENTIFIER(append);
static int
specialize_method_descriptor(
PyMethodDescrObject *descr, _Py_CODEUNIT *instr,
int nargs, SpecializedCacheEntry *cache)
{
int oparg = cache->adaptive.original_oparg;
if (nargs - oparg != 1) {
SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_METHDESCR_NON_METHOD);
return -1;
}
if (_list_append == NULL) {
_list_append = (PyMethodDescrObject *)_PyType_LookupId(&PyList_Type, &PyId_append);
}
if (oparg == 1 && descr == _list_append) {
assert(_Py_OPCODE(instr[-1]) == PRECALL_METHOD);
*instr = _Py_MAKECODEUNIT(CALL_NO_KW_LIST_APPEND, _Py_OPARG(*instr));
return 0;
}
switch (descr->d_method->ml_flags &
(METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O |
METH_KEYWORDS | METH_METHOD)) {
case METH_O: {
if (oparg != 1) {
SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_OUT_OF_RANGE);
return 1;
}
*instr = _Py_MAKECODEUNIT(CALL_NO_KW_METHOD_DESCRIPTOR_O,
_Py_OPARG(*instr));
return 0;
}
case METH_FASTCALL: {
*instr = _Py_MAKECODEUNIT(CALL_NO_KW_METHOD_DESCRIPTOR_FAST,
_Py_OPARG(*instr));
return 0;
}
}
SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_OTHER);
return -1; return -1;
} }
@ -1274,15 +1320,19 @@ specialize_py_call(
PyCodeObject *code = (PyCodeObject *)func->func_code; PyCodeObject *code = (PyCodeObject *)func->func_code;
int kind = function_kind(code); int kind = function_kind(code);
if (kind != SIMPLE_FUNCTION) { if (kind != SIMPLE_FUNCTION) {
SPECIALIZATION_FAIL(CALL_FUNCTION, kind); SPECIALIZATION_FAIL(CALL_NO_KW, kind);
return -1; return -1;
} }
int argcount = code->co_argcount; int argcount = code->co_argcount;
if (argcount > 0xffff) {
SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_OUT_OF_RANGE);
return -1;
}
int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults); int defcount = func->func_defaults == NULL ? 0 : (int)PyTuple_GET_SIZE(func->func_defaults);
assert(defcount <= argcount); assert(defcount <= argcount);
int min_args = argcount-defcount; int min_args = argcount-defcount;
if (nargs > argcount || nargs < min_args) { if (nargs > argcount || nargs < min_args) {
SPECIALIZATION_FAIL(CALL_FUNCTION, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS);
return -1; return -1;
} }
assert(nargs <= argcount && nargs >= min_args); assert(nargs <= argcount && nargs >= min_args);
@ -1291,18 +1341,19 @@ specialize_py_call(
assert(defstart >= 0 && deflen >= 0); assert(defstart >= 0 && deflen >= 0);
assert(deflen == 0 || func->func_defaults != NULL); assert(deflen == 0 || func->func_defaults != NULL);
if (defstart > 0xffff || deflen > 0xffff) { if (defstart > 0xffff || deflen > 0xffff) {
SPECIALIZATION_FAIL(CALL_FUNCTION, SPEC_FAIL_OUT_OF_RANGE); SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_OUT_OF_RANGE);
return -1; return -1;
} }
int version = _PyFunction_GetVersionForCurrentState(func); int version = _PyFunction_GetVersionForCurrentState(func);
if (version == 0) { if (version == 0) {
SPECIALIZATION_FAIL(CALL_FUNCTION, SPEC_FAIL_OUT_OF_VERSIONS); SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_OUT_OF_VERSIONS);
return -1; return -1;
} }
cache[0].adaptive.index = nargs;
cache1->func_version = version; cache1->func_version = version;
cache1->defaults_start = defstart; cache1->defaults_start = defstart;
cache1->defaults_len = deflen; cache1->defaults_len = deflen;
*instr = _Py_MAKECODEUNIT(CALL_FUNCTION_PY_SIMPLE, _Py_OPARG(*instr)); *instr = _Py_MAKECODEUNIT(CALL_NO_KW_PY_SIMPLE, _Py_OPARG(*instr));
return 0; return 0;
} }
@ -1335,6 +1386,10 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
SpecializedCacheEntry *cache, PyObject *builtins) SpecializedCacheEntry *cache, PyObject *builtins)
{ {
_PyObjectCache *cache1 = &cache[-1].obj; _PyObjectCache *cache1 = &cache[-1].obj;
if (_Py_OPCODE(instr[-1]) == PRECALL_METHOD) {
SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_C_METHOD_CALL);
return -1;
}
if (PyCFunction_GET_FUNCTION(callable) == NULL) { if (PyCFunction_GET_FUNCTION(callable) == NULL) {
return 1; return 1;
} }
@ -1343,18 +1398,18 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
METH_KEYWORDS | METH_METHOD)) { METH_KEYWORDS | METH_METHOD)) {
case METH_O: { case METH_O: {
if (nargs != 1) { if (nargs != 1) {
SPECIALIZATION_FAIL(CALL_FUNCTION, SPEC_FAIL_OUT_OF_RANGE); SPECIALIZATION_FAIL(CALL_NO_KW, SPEC_FAIL_OUT_OF_RANGE);
return 1; return 1;
} }
/* len(o) */ /* len(o) */
PyObject *builtin_len = PyDict_GetItemString(builtins, "len"); PyObject *builtin_len = PyDict_GetItemString(builtins, "len");
if (callable == builtin_len) { if (callable == builtin_len) {
cache1->obj = builtin_len; // borrowed cache1->obj = builtin_len; // borrowed
*instr = _Py_MAKECODEUNIT(CALL_FUNCTION_LEN, *instr = _Py_MAKECODEUNIT(CALL_NO_KW_LEN,
_Py_OPARG(*instr)); _Py_OPARG(*instr));
return 0; return 0;
} }
*instr = _Py_MAKECODEUNIT(CALL_FUNCTION_BUILTIN_O, *instr = _Py_MAKECODEUNIT(CALL_NO_KW_BUILTIN_O,
_Py_OPARG(*instr)); _Py_OPARG(*instr));
return 0; return 0;
} }
@ -1365,17 +1420,17 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
builtins, "isinstance"); builtins, "isinstance");
if (callable == builtin_isinstance) { if (callable == builtin_isinstance) {
cache1->obj = builtin_isinstance; // borrowed cache1->obj = builtin_isinstance; // borrowed
*instr = _Py_MAKECODEUNIT(CALL_FUNCTION_ISINSTANCE, *instr = _Py_MAKECODEUNIT(CALL_NO_KW_ISINSTANCE,
_Py_OPARG(*instr)); _Py_OPARG(*instr));
return 0; return 0;
} }
} }
*instr = _Py_MAKECODEUNIT(CALL_FUNCTION_BUILTIN_FAST, *instr = _Py_MAKECODEUNIT(CALL_NO_KW_BUILTIN_FAST,
_Py_OPARG(*instr)); _Py_OPARG(*instr));
return 0; return 0;
} }
default: default:
SPECIALIZATION_FAIL(CALL_FUNCTION, SPECIALIZATION_FAIL(CALL_NO_KW,
builtin_call_fail_kind(PyCFunction_GET_FLAGS(callable))); builtin_call_fail_kind(PyCFunction_GET_FLAGS(callable)));
return 1; return 1;
} }
@ -1406,7 +1461,7 @@ call_fail_kind(PyObject *callable)
- Specialize calling classes. - Specialize calling classes.
*/ */
int int
_Py_Specialize_CallFunction( _Py_Specialize_CallNoKw(
PyObject *callable, _Py_CODEUNIT *instr, PyObject *callable, _Py_CODEUNIT *instr,
int nargs, SpecializedCacheEntry *cache, int nargs, SpecializedCacheEntry *cache,
PyObject *builtins) PyObject *builtins)
@ -1421,18 +1476,22 @@ _Py_Specialize_CallFunction(
else if (PyType_Check(callable)) { else if (PyType_Check(callable)) {
fail = specialize_class_call(callable, instr, nargs, cache); fail = specialize_class_call(callable, instr, nargs, cache);
} }
else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) {
fail = specialize_method_descriptor(
(PyMethodDescrObject *)callable, instr, nargs, cache);
}
else { else {
SPECIALIZATION_FAIL(CALL_FUNCTION, call_fail_kind(callable)); SPECIALIZATION_FAIL(CALL_NO_KW, call_fail_kind(callable));
fail = -1; fail = -1;
} }
_PyAdaptiveEntry *cache0 = &cache->adaptive; _PyAdaptiveEntry *cache0 = &cache->adaptive;
if (fail) { if (fail) {
STAT_INC(CALL_FUNCTION, specialization_failure); STAT_INC(CALL_NO_KW, specialization_failure);
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
cache_backoff(cache0); cache_backoff(cache0);
} }
else { else {
STAT_INC(CALL_FUNCTION, specialization_success); STAT_INC(CALL_NO_KW, specialization_success);
assert(!PyErr_Occurred()); assert(!PyErr_Occurred());
cache0->counter = initial_counter_value(); cache0->counter = initial_counter_value();
} }