mirror of
				https://github.com/python/cpython.git
				synced 2025-11-01 06:01:29 +00:00 
			
		
		
		
	bpo-46528: Simplify the VM's stack manipulations (GH-30902)
This commit is contained in:
		
							parent
							
								
									d4a85f104b
								
							
						
					
					
						commit
						8548366864
					
				
					 12 changed files with 288 additions and 323 deletions
				
			
		|  | @ -348,7 +348,8 @@ The Python compiler currently generates the following bytecode instructions. | ||||||
| 
 | 
 | ||||||
| .. opcode:: NOP | .. opcode:: NOP | ||||||
| 
 | 
 | ||||||
|    Do nothing code.  Used as a placeholder by the bytecode optimizer. |    Do nothing code.  Used as a placeholder by the bytecode optimizer, and to | ||||||
|  |    generate line tracing events. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. opcode:: POP_TOP | .. opcode:: POP_TOP | ||||||
|  | @ -356,38 +357,19 @@ The Python compiler currently generates the following bytecode instructions. | ||||||
|    Removes the top-of-stack (TOS) item. |    Removes the top-of-stack (TOS) item. | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. opcode:: ROT_TWO | .. opcode:: COPY (i) | ||||||
| 
 | 
 | ||||||
|    Swaps the two top-most stack items. |    Push the *i*-th item to the top of the stack. The item is not removed from its | ||||||
|  |    original location. | ||||||
|  | 
 | ||||||
|  |    .. versionadded:: 3.11 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. opcode:: ROT_THREE | .. opcode:: SWAP (i) | ||||||
| 
 | 
 | ||||||
|    Lifts second and third stack item one position up, moves top down to position |    Swap TOS with the item at position *i*. | ||||||
|    three. |  | ||||||
| 
 | 
 | ||||||
| 
 |    .. versionadded:: 3.11 | ||||||
| .. opcode:: ROT_FOUR |  | ||||||
| 
 |  | ||||||
|    Lifts second, third and fourth stack items one position up, moves top down |  | ||||||
|    to position four. |  | ||||||
| 
 |  | ||||||
|    .. versionadded:: 3.8 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| .. opcode:: DUP_TOP |  | ||||||
| 
 |  | ||||||
|    Duplicates the reference on top of the stack. |  | ||||||
| 
 |  | ||||||
|    .. versionadded:: 3.2 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| .. opcode:: DUP_TOP_TWO |  | ||||||
| 
 |  | ||||||
|    Duplicates the two references on top of the stack, leaving them in the |  | ||||||
|    same order. |  | ||||||
| 
 |  | ||||||
|    .. versionadded:: 3.2 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| **Unary operations** | **Unary operations** | ||||||
|  | @ -689,8 +671,6 @@ iterations of the loop. | ||||||
|       success (``True``) or failure (``False``). |       success (``True``) or failure (``False``). | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| All of the following opcodes use their arguments. |  | ||||||
| 
 |  | ||||||
| .. opcode:: STORE_NAME (namei) | .. opcode:: STORE_NAME (namei) | ||||||
| 
 | 
 | ||||||
|    Implements ``name = TOS``. *namei* is the index of *name* in the attribute |    Implements ``name = TOS``. *namei* is the index of *name* in the attribute | ||||||
|  | @ -1217,22 +1197,6 @@ All of the following opcodes use their arguments. | ||||||
|       success (``True``) or failure (``False``). |       success (``True``) or failure (``False``). | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| .. opcode:: ROT_N (count) |  | ||||||
| 
 |  | ||||||
|    Lift the top *count* stack items one position up, and move TOS down to |  | ||||||
|    position *count*. |  | ||||||
| 
 |  | ||||||
|    .. versionadded:: 3.10 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| .. opcode:: COPY (i) |  | ||||||
| 
 |  | ||||||
|    Push the *i*-th item to the top of the stack. The item is not removed from its |  | ||||||
|    original location. |  | ||||||
| 
 |  | ||||||
|    .. versionadded:: 3.11 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| .. opcode:: RESUME (where) | .. opcode:: RESUME (where) | ||||||
| 
 | 
 | ||||||
|     A no-op. Performs internal tracing, debugging and optimization checks. |     A no-op. Performs internal tracing, debugging and optimization checks. | ||||||
|  |  | ||||||
|  | @ -411,8 +411,9 @@ CPython bytecode changes | ||||||
|   indicate failure with :const:`None` (where a tuple of extracted values would |   indicate failure with :const:`None` (where a tuple of extracted values would | ||||||
|   otherwise be). |   otherwise be). | ||||||
| 
 | 
 | ||||||
| * Added :opcode:`COPY`, which pushes the *i*-th item to the top of the stack. | * Replace several stack manipulation instructions (``DUP_TOP``, ``DUP_TOP_TWO``, | ||||||
|   The item is not removed from its original location. |   ``ROT_TWO``, ``ROT_THREE``, ``ROT_FOUR``, and ``ROT_N``) with new | ||||||
|  |   :opcode:`COPY` and :opcode:`SWAP` instructions. | ||||||
| 
 | 
 | ||||||
| * Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to | * Add :opcode:`POP_JUMP_IF_NOT_NONE` and :opcode:`POP_JUMP_IF_NONE` opcodes to | ||||||
|   speed up conditional jumps. |   speed up conditional jumps. | ||||||
|  |  | ||||||
							
								
								
									
										117
									
								
								Include/opcode.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										117
									
								
								Include/opcode.h
									
										
									
										generated
									
									
									
								
							|  | @ -8,11 +8,6 @@ extern "C" { | ||||||
| 
 | 
 | ||||||
| /* Instruction opcodes for compiled code */ | /* Instruction opcodes for compiled code */ | ||||||
| #define POP_TOP                           1 | #define POP_TOP                           1 | ||||||
| #define ROT_TWO                           2 |  | ||||||
| #define ROT_THREE                         3 |  | ||||||
| #define DUP_TOP                           4 |  | ||||||
| #define DUP_TOP_TWO                       5 |  | ||||||
| #define ROT_FOUR                          6 |  | ||||||
| #define NOP                               9 | #define NOP                               9 | ||||||
| #define UNARY_POSITIVE                   10 | #define UNARY_POSITIVE                   10 | ||||||
| #define UNARY_NEGATIVE                   11 | #define UNARY_NEGATIVE                   11 | ||||||
|  | @ -57,7 +52,7 @@ extern "C" { | ||||||
| #define DELETE_ATTR                      96 | #define DELETE_ATTR                      96 | ||||||
| #define STORE_GLOBAL                     97 | #define STORE_GLOBAL                     97 | ||||||
| #define DELETE_GLOBAL                    98 | #define DELETE_GLOBAL                    98 | ||||||
| #define ROT_N                            99 | #define SWAP                             99 | ||||||
| #define LOAD_CONST                      100 | #define LOAD_CONST                      100 | ||||||
| #define LOAD_NAME                       101 | #define LOAD_NAME                       101 | ||||||
| #define BUILD_TUPLE                     102 | #define BUILD_TUPLE                     102 | ||||||
|  | @ -117,61 +112,61 @@ extern "C" { | ||||||
| #define PRECALL_METHOD                  168 | #define PRECALL_METHOD                  168 | ||||||
| #define CALL_NO_KW                      169 | #define CALL_NO_KW                      169 | ||||||
| #define CALL_KW                         170 | #define CALL_KW                         170 | ||||||
| #define BINARY_OP_ADAPTIVE                7 | #define BINARY_OP_ADAPTIVE                2 | ||||||
| #define BINARY_OP_ADD_INT                 8 | #define BINARY_OP_ADD_INT                 3 | ||||||
| #define BINARY_OP_ADD_FLOAT              13 | #define BINARY_OP_ADD_FLOAT               4 | ||||||
| #define BINARY_OP_ADD_UNICODE            14 | #define BINARY_OP_ADD_UNICODE             5 | ||||||
| #define BINARY_OP_INPLACE_ADD_UNICODE    16 | #define BINARY_OP_INPLACE_ADD_UNICODE     6 | ||||||
| #define BINARY_OP_MULTIPLY_INT           17 | #define BINARY_OP_MULTIPLY_INT            7 | ||||||
| #define BINARY_OP_MULTIPLY_FLOAT         18 | #define BINARY_OP_MULTIPLY_FLOAT          8 | ||||||
| #define BINARY_OP_SUBTRACT_INT           19 | #define BINARY_OP_SUBTRACT_INT           13 | ||||||
| #define BINARY_OP_SUBTRACT_FLOAT         20 | #define BINARY_OP_SUBTRACT_FLOAT         14 | ||||||
| #define COMPARE_OP_ADAPTIVE              21 | #define COMPARE_OP_ADAPTIVE              16 | ||||||
| #define COMPARE_OP_FLOAT_JUMP            22 | #define COMPARE_OP_FLOAT_JUMP            17 | ||||||
| #define COMPARE_OP_INT_JUMP              23 | #define COMPARE_OP_INT_JUMP              18 | ||||||
| #define COMPARE_OP_STR_JUMP              24 | #define COMPARE_OP_STR_JUMP              19 | ||||||
| #define BINARY_SUBSCR_ADAPTIVE           26 | #define BINARY_SUBSCR_ADAPTIVE           20 | ||||||
| #define BINARY_SUBSCR_GETITEM            27 | #define BINARY_SUBSCR_GETITEM            21 | ||||||
| #define BINARY_SUBSCR_LIST_INT           28 | #define BINARY_SUBSCR_LIST_INT           22 | ||||||
| #define BINARY_SUBSCR_TUPLE_INT          29 | #define BINARY_SUBSCR_TUPLE_INT          23 | ||||||
| #define BINARY_SUBSCR_DICT               34 | #define BINARY_SUBSCR_DICT               24 | ||||||
| #define STORE_SUBSCR_ADAPTIVE            36 | #define STORE_SUBSCR_ADAPTIVE            26 | ||||||
| #define STORE_SUBSCR_LIST_INT            37 | #define STORE_SUBSCR_LIST_INT            27 | ||||||
| #define STORE_SUBSCR_DICT                38 | #define STORE_SUBSCR_DICT                28 | ||||||
| #define CALL_NO_KW_ADAPTIVE              39 | #define CALL_NO_KW_ADAPTIVE              29 | ||||||
| #define CALL_NO_KW_BUILTIN_O             40 | #define CALL_NO_KW_BUILTIN_O             34 | ||||||
| #define CALL_NO_KW_BUILTIN_FAST          41 | #define CALL_NO_KW_BUILTIN_FAST          36 | ||||||
| #define CALL_NO_KW_LEN                   42 | #define CALL_NO_KW_LEN                   37 | ||||||
| #define CALL_NO_KW_ISINSTANCE            43 | #define CALL_NO_KW_ISINSTANCE            38 | ||||||
| #define CALL_NO_KW_PY_SIMPLE             44 | #define CALL_NO_KW_PY_SIMPLE             39 | ||||||
| #define CALL_NO_KW_LIST_APPEND           45 | #define CALL_NO_KW_LIST_APPEND           40 | ||||||
| #define CALL_NO_KW_METHOD_DESCRIPTOR_O   46 | #define CALL_NO_KW_METHOD_DESCRIPTOR_O   41 | ||||||
| #define CALL_NO_KW_TYPE_1                47 | #define CALL_NO_KW_TYPE_1                42 | ||||||
| #define CALL_NO_KW_BUILTIN_CLASS_1       48 | #define CALL_NO_KW_BUILTIN_CLASS_1       43 | ||||||
| #define CALL_NO_KW_METHOD_DESCRIPTOR_FAST  55 | #define CALL_NO_KW_METHOD_DESCRIPTOR_FAST  44 | ||||||
| #define JUMP_ABSOLUTE_QUICK              56 | #define JUMP_ABSOLUTE_QUICK              45 | ||||||
| #define LOAD_ATTR_ADAPTIVE               57 | #define LOAD_ATTR_ADAPTIVE               46 | ||||||
| #define LOAD_ATTR_INSTANCE_VALUE         58 | #define LOAD_ATTR_INSTANCE_VALUE         47 | ||||||
| #define LOAD_ATTR_WITH_HINT              59 | #define LOAD_ATTR_WITH_HINT              48 | ||||||
| #define LOAD_ATTR_SLOT                   62 | #define LOAD_ATTR_SLOT                   55 | ||||||
| #define LOAD_ATTR_MODULE                 63 | #define LOAD_ATTR_MODULE                 56 | ||||||
| #define LOAD_GLOBAL_ADAPTIVE             64 | #define LOAD_GLOBAL_ADAPTIVE             57 | ||||||
| #define LOAD_GLOBAL_MODULE               65 | #define LOAD_GLOBAL_MODULE               58 | ||||||
| #define LOAD_GLOBAL_BUILTIN              66 | #define LOAD_GLOBAL_BUILTIN              59 | ||||||
| #define LOAD_METHOD_ADAPTIVE             67 | #define LOAD_METHOD_ADAPTIVE             62 | ||||||
| #define LOAD_METHOD_CACHED               72 | #define LOAD_METHOD_CACHED               63 | ||||||
| #define LOAD_METHOD_CLASS                76 | #define LOAD_METHOD_CLASS                64 | ||||||
| #define LOAD_METHOD_MODULE               77 | #define LOAD_METHOD_MODULE               65 | ||||||
| #define LOAD_METHOD_NO_DICT              78 | #define LOAD_METHOD_NO_DICT              66 | ||||||
| #define STORE_ATTR_ADAPTIVE              79 | #define STORE_ATTR_ADAPTIVE              67 | ||||||
| #define STORE_ATTR_INSTANCE_VALUE        80 | #define STORE_ATTR_INSTANCE_VALUE        72 | ||||||
| #define STORE_ATTR_SLOT                  81 | #define STORE_ATTR_SLOT                  76 | ||||||
| #define STORE_ATTR_WITH_HINT            131 | #define STORE_ATTR_WITH_HINT             77 | ||||||
| #define LOAD_FAST__LOAD_FAST            140 | #define LOAD_FAST__LOAD_FAST             78 | ||||||
| #define STORE_FAST__LOAD_FAST           141 | #define STORE_FAST__LOAD_FAST            79 | ||||||
| #define LOAD_FAST__LOAD_CONST           143 | #define LOAD_FAST__LOAD_CONST            80 | ||||||
| #define LOAD_CONST__LOAD_FAST           150 | #define LOAD_CONST__LOAD_FAST            81 | ||||||
| #define STORE_FAST__STORE_FAST          153 | #define STORE_FAST__STORE_FAST          131 | ||||||
| #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] = { | ||||||
|  |  | ||||||
|  | @ -382,6 +382,8 @@ def _write_atomic(path, data, mode=0o666): | ||||||
| #     Python 3.11a4 3474 (Add RESUME opcode) | #     Python 3.11a4 3474 (Add RESUME opcode) | ||||||
| #     Python 3.11a5 3475 (Add RETURN_GENERATOR opcode) | #     Python 3.11a5 3475 (Add RETURN_GENERATOR opcode) | ||||||
| #     Python 3.11a5 3476 (Add ASYNC_GEN_WRAP opcode) | #     Python 3.11a5 3476 (Add ASYNC_GEN_WRAP opcode) | ||||||
|  | #     Python 3.11a5 3477 (Replace DUP_TOP/DUP_TOP_TWO with COPY and | ||||||
|  | #                         ROT_TWO/ROT_THREE/ROT_FOUR/ROT_N with SWAP) | ||||||
| 
 | 
 | ||||||
| #     Python 3.12 will start with magic number 3500 | #     Python 3.12 will start with magic number 3500 | ||||||
| 
 | 
 | ||||||
|  | @ -395,7 +397,7 @@ def _write_atomic(path, data, mode=0o666): | ||||||
| # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array | # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array | ||||||
| # in PC/launcher.c must also be updated. | # in PC/launcher.c must also be updated. | ||||||
| 
 | 
 | ||||||
| MAGIC_NUMBER = (3476).to_bytes(2, 'little') + b'\r\n' | MAGIC_NUMBER = (3477).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__' | ||||||
|  |  | ||||||
|  | @ -55,11 +55,6 @@ def jabs_op(name, op): | ||||||
| # Blank lines correspond to available opcodes | # Blank lines correspond to available opcodes | ||||||
| 
 | 
 | ||||||
| def_op('POP_TOP', 1) | def_op('POP_TOP', 1) | ||||||
| def_op('ROT_TWO', 2) |  | ||||||
| def_op('ROT_THREE', 3) |  | ||||||
| def_op('DUP_TOP', 4) |  | ||||||
| def_op('DUP_TOP_TWO', 5) |  | ||||||
| def_op('ROT_FOUR', 6) |  | ||||||
| 
 | 
 | ||||||
| def_op('NOP', 9) | def_op('NOP', 9) | ||||||
| def_op('UNARY_POSITIVE', 10) | def_op('UNARY_POSITIVE', 10) | ||||||
|  | @ -116,7 +111,7 @@ def jabs_op(name, op): | ||||||
| name_op('DELETE_ATTR', 96)      # "" | name_op('DELETE_ATTR', 96)      # "" | ||||||
| name_op('STORE_GLOBAL', 97)     # "" | name_op('STORE_GLOBAL', 97)     # "" | ||||||
| name_op('DELETE_GLOBAL', 98)    # "" | name_op('DELETE_GLOBAL', 98)    # "" | ||||||
| def_op('ROT_N', 99) | def_op('SWAP', 99) | ||||||
| def_op('LOAD_CONST', 100)       # Index in const list | def_op('LOAD_CONST', 100)       # Index in const list | ||||||
| hasconst.append(100) | hasconst.append(100) | ||||||
| name_op('LOAD_NAME', 101)       # Index in name list | name_op('LOAD_NAME', 101)       # Index in name list | ||||||
|  |  | ||||||
|  | @ -11,7 +11,6 @@ class OpcodeTests(unittest.TestCase): | ||||||
| 
 | 
 | ||||||
|     def test_stack_effect(self): |     def test_stack_effect(self): | ||||||
|         self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1) |         self.assertEqual(stack_effect(dis.opmap['POP_TOP']), -1) | ||||||
|         self.assertEqual(stack_effect(dis.opmap['DUP_TOP_TWO']), 2) |  | ||||||
|         self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1) |         self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 0), -1) | ||||||
|         self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1) |         self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 1), -1) | ||||||
|         self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2) |         self.assertEqual(stack_effect(dis.opmap['BUILD_SLICE'], 3), -2) | ||||||
|  |  | ||||||
|  | @ -1195,8 +1195,8 @@ def _prepare_test_cases(): | ||||||
|   Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None), |   Instruction(opname='CALL_NO_KW', opcode=169, arg=1, argval=1, argrepr='', offset=156, starts_line=None, is_jump_target=False, positions=None), | ||||||
|   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=158, starts_line=None, is_jump_target=False, positions=None), |   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=158, starts_line=None, is_jump_target=False, positions=None), | ||||||
|   Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=160, starts_line=25, is_jump_target=False, positions=None), |   Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=160, starts_line=25, 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='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=162, starts_line=None, is_jump_target=False, positions=None), | ||||||
|   Instruction(opname='DUP_TOP', opcode=4, arg=None, argval=None, argrepr='', offset=164, starts_line=None, is_jump_target=False, positions=None), |   Instruction(opname='LOAD_CONST', opcode=100, arg=0, argval=None, argrepr='None', offset=164, starts_line=None, is_jump_target=False, positions=None), | ||||||
|   Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None), |   Instruction(opname='CALL_NO_KW', opcode=169, arg=3, argval=3, argrepr='', offset=166, starts_line=None, is_jump_target=False, positions=None), | ||||||
|   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None), |   Instruction(opname='POP_TOP', opcode=1, arg=None, argval=None, argrepr='', offset=168, starts_line=None, is_jump_target=False, positions=None), | ||||||
|   Instruction(opname='JUMP_FORWARD', opcode=110, arg=25, argval=222, argrepr='to 222', offset=170, starts_line=None, is_jump_target=False, positions=None), |   Instruction(opname='JUMP_FORWARD', opcode=110, arg=25, argval=222, argrepr='to 222', offset=170, starts_line=None, is_jump_target=False, positions=None), | ||||||
|  |  | ||||||
|  | @ -119,8 +119,8 @@ def f(): | ||||||
|     def test_pack_unpack(self): |     def test_pack_unpack(self): | ||||||
|         for line, elem in ( |         for line, elem in ( | ||||||
|             ('a, = a,', 'LOAD_CONST',), |             ('a, = a,', 'LOAD_CONST',), | ||||||
|             ('a, b = a, b', 'ROT_TWO',), |             ('a, b = a, b', 'SWAP',), | ||||||
|             ('a, b, c = a, b, c', 'ROT_THREE',), |             ('a, b, c = a, b, c', 'SWAP',), | ||||||
|             ): |             ): | ||||||
|             with self.subTest(line=line): |             with self.subTest(line=line): | ||||||
|                 code = compile(line,'','single') |                 code = compile(line,'','single') | ||||||
|  |  | ||||||
|  | @ -0,0 +1,3 @@ | ||||||
|  | Replace several stack manipulation instructions (``DUP_TOP``, | ||||||
|  | ``DUP_TOP_TWO``, ``ROT_TWO``, ``ROT_THREE``, ``ROT_FOUR``, and ``ROT_N``) | ||||||
|  | with new :opcode:`COPY` and :opcode:`SWAP` instructions. | ||||||
|  | @ -1434,8 +1434,6 @@ eval_frame_handle_pending(PyThreadState *tstate) | ||||||
| #define PEEK(n)           (stack_pointer[-(n)]) | #define PEEK(n)           (stack_pointer[-(n)]) | ||||||
| #define SET_TOP(v)        (stack_pointer[-1] = (v)) | #define SET_TOP(v)        (stack_pointer[-1] = (v)) | ||||||
| #define SET_SECOND(v)     (stack_pointer[-2] = (v)) | #define SET_SECOND(v)     (stack_pointer[-2] = (v)) | ||||||
| #define SET_THIRD(v)      (stack_pointer[-3] = (v)) |  | ||||||
| #define SET_FOURTH(v)     (stack_pointer[-4] = (v)) |  | ||||||
| #define BASIC_STACKADJ(n) (stack_pointer += n) | #define BASIC_STACKADJ(n) (stack_pointer += n) | ||||||
| #define BASIC_PUSH(v)     (*stack_pointer++ = (v)) | #define BASIC_PUSH(v)     (*stack_pointer++ = (v)) | ||||||
| #define BASIC_POP()       (*--stack_pointer) | #define BASIC_POP()       (*--stack_pointer) | ||||||
|  | @ -1920,54 +1918,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | ||||||
|             DISPATCH(); |             DISPATCH(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         TARGET(ROT_TWO) { |  | ||||||
|             PyObject *top = TOP(); |  | ||||||
|             PyObject *second = SECOND(); |  | ||||||
|             SET_TOP(second); |  | ||||||
|             SET_SECOND(top); |  | ||||||
|             DISPATCH(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         TARGET(ROT_THREE) { |  | ||||||
|             PyObject *top = TOP(); |  | ||||||
|             PyObject *second = SECOND(); |  | ||||||
|             PyObject *third = THIRD(); |  | ||||||
|             SET_TOP(second); |  | ||||||
|             SET_SECOND(third); |  | ||||||
|             SET_THIRD(top); |  | ||||||
|             DISPATCH(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         TARGET(ROT_FOUR) { |  | ||||||
|             PyObject *top = TOP(); |  | ||||||
|             PyObject *second = SECOND(); |  | ||||||
|             PyObject *third = THIRD(); |  | ||||||
|             PyObject *fourth = FOURTH(); |  | ||||||
|             SET_TOP(second); |  | ||||||
|             SET_SECOND(third); |  | ||||||
|             SET_THIRD(fourth); |  | ||||||
|             SET_FOURTH(top); |  | ||||||
|             DISPATCH(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         TARGET(DUP_TOP) { |  | ||||||
|             PyObject *top = TOP(); |  | ||||||
|             Py_INCREF(top); |  | ||||||
|             PUSH(top); |  | ||||||
|             DISPATCH(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         TARGET(DUP_TOP_TWO) { |  | ||||||
|             PyObject *top = TOP(); |  | ||||||
|             PyObject *second = SECOND(); |  | ||||||
|             Py_INCREF(top); |  | ||||||
|             Py_INCREF(second); |  | ||||||
|             STACK_GROW(2); |  | ||||||
|             SET_TOP(top); |  | ||||||
|             SET_SECOND(second); |  | ||||||
|             DISPATCH(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         TARGET(UNARY_POSITIVE) { |         TARGET(UNARY_POSITIVE) { | ||||||
|             PyObject *value = TOP(); |             PyObject *value = TOP(); | ||||||
|             PyObject *res = PyNumber_Positive(value); |             PyObject *res = PyNumber_Positive(value); | ||||||
|  | @ -5170,14 +5120,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | ||||||
|             DISPATCH(); |             DISPATCH(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         TARGET(ROT_N) { |  | ||||||
|             PyObject *top = TOP(); |  | ||||||
|             memmove(&PEEK(oparg - 1), &PEEK(oparg), |  | ||||||
|                     sizeof(PyObject*) * (oparg - 1)); |  | ||||||
|             PEEK(oparg) = top; |  | ||||||
|             DISPATCH(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         TARGET(COPY) { |         TARGET(COPY) { | ||||||
|             assert(oparg != 0); |             assert(oparg != 0); | ||||||
|             PyObject *peek = PEEK(oparg); |             PyObject *peek = PEEK(oparg); | ||||||
|  | @ -5221,6 +5163,14 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         TARGET(SWAP) { | ||||||
|  |             assert(oparg != 0); | ||||||
|  |             PyObject *top = TOP(); | ||||||
|  |             SET_TOP(PEEK(oparg)); | ||||||
|  |             PEEK(oparg) = top; | ||||||
|  |             DISPATCH(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         TARGET(EXTENDED_ARG) { |         TARGET(EXTENDED_ARG) { | ||||||
|             int oldoparg = oparg; |             int oldoparg = oparg; | ||||||
|             NEXTOPARG(); |             NEXTOPARG(); | ||||||
|  | @ -7380,7 +7330,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_NO_KW && prevprevopcode == DUP_TOP)) { |         else if (prevopcode == WITH_EXCEPT_START || (prevopcode == CALL_NO_KW && prevprevopcode == LOAD_CONST)) { | ||||||
|             _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", | ||||||
|  |  | ||||||
							
								
								
									
										266
									
								
								Python/compile.c
									
										
									
									
									
								
							
							
						
						
									
										266
									
								
								Python/compile.c
									
										
									
									
									
								
							|  | @ -867,14 +867,8 @@ stack_effect(int opcode, int oparg, int jump) | ||||||
|         /* Stack manipulation */ |         /* Stack manipulation */ | ||||||
|         case POP_TOP: |         case POP_TOP: | ||||||
|             return -1; |             return -1; | ||||||
|         case ROT_TWO: |         case SWAP: | ||||||
|         case ROT_THREE: |  | ||||||
|         case ROT_FOUR: |  | ||||||
|             return 0; |             return 0; | ||||||
|         case DUP_TOP: |  | ||||||
|             return 1; |  | ||||||
|         case DUP_TOP_TWO: |  | ||||||
|             return 2; |  | ||||||
| 
 | 
 | ||||||
|         /* Unary operators */ |         /* Unary operators */ | ||||||
|         case UNARY_POSITIVE: |         case UNARY_POSITIVE: | ||||||
|  | @ -1094,8 +1088,6 @@ stack_effect(int opcode, int oparg, int jump) | ||||||
|         case MATCH_SEQUENCE: |         case MATCH_SEQUENCE: | ||||||
|         case MATCH_KEYS: |         case MATCH_KEYS: | ||||||
|             return 1; |             return 1; | ||||||
|         case ROT_N: |  | ||||||
|             return 0; |  | ||||||
|         case COPY: |         case COPY: | ||||||
|             return 1; |             return 1; | ||||||
|         case BINARY_OP: |         case BINARY_OP: | ||||||
|  | @ -1829,8 +1821,8 @@ compiler_pop_fblock(struct compiler *c, enum fblocktype t, basicblock *b) | ||||||
| static int | static int | ||||||
| compiler_call_exit_with_nones(struct compiler *c) { | 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_LOAD_CONST(c, Py_None); | ||||||
|     ADDOP(c, DUP_TOP); |     ADDOP_LOAD_CONST(c, Py_None); | ||||||
|     ADDOP_I(c, CALL_NO_KW, 3); |     ADDOP_I(c, CALL_NO_KW, 3); | ||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
|  | @ -1890,7 +1882,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, | ||||||
|         case FOR_LOOP: |         case FOR_LOOP: | ||||||
|             /* Pop the iterator */ |             /* Pop the iterator */ | ||||||
|             if (preserve_tos) { |             if (preserve_tos) { | ||||||
|                 ADDOP(c, ROT_TWO); |                 ADDOP_I(c, SWAP, 2); | ||||||
|             } |             } | ||||||
|             ADDOP(c, POP_TOP); |             ADDOP(c, POP_TOP); | ||||||
|             return 1; |             return 1; | ||||||
|  | @ -1920,11 +1912,11 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, | ||||||
| 
 | 
 | ||||||
|         case FINALLY_END: |         case FINALLY_END: | ||||||
|             if (preserve_tos) { |             if (preserve_tos) { | ||||||
|                 ADDOP(c, ROT_TWO); |                 ADDOP_I(c, SWAP, 2); | ||||||
|             } |             } | ||||||
|             ADDOP(c, POP_TOP); /* exc_value */ |             ADDOP(c, POP_TOP); /* exc_value */ | ||||||
|             if (preserve_tos) { |             if (preserve_tos) { | ||||||
|                 ADDOP(c, ROT_TWO); |                 ADDOP_I(c, SWAP, 2); | ||||||
|             } |             } | ||||||
|             ADDOP(c, POP_BLOCK); |             ADDOP(c, POP_BLOCK); | ||||||
|             ADDOP(c, POP_EXCEPT); |             ADDOP(c, POP_EXCEPT); | ||||||
|  | @ -1935,7 +1927,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, | ||||||
|             SET_LOC(c, (stmt_ty)info->fb_datum); |             SET_LOC(c, (stmt_ty)info->fb_datum); | ||||||
|             ADDOP(c, POP_BLOCK); |             ADDOP(c, POP_BLOCK); | ||||||
|             if (preserve_tos) { |             if (preserve_tos) { | ||||||
|                 ADDOP(c, ROT_TWO); |                 ADDOP_I(c, SWAP, 2); | ||||||
|             } |             } | ||||||
|             if(!compiler_call_exit_with_nones(c)) { |             if(!compiler_call_exit_with_nones(c)) { | ||||||
|                 return 0; |                 return 0; | ||||||
|  | @ -1957,7 +1949,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, | ||||||
|                 ADDOP(c, POP_BLOCK); |                 ADDOP(c, POP_BLOCK); | ||||||
|             } |             } | ||||||
|             if (preserve_tos) { |             if (preserve_tos) { | ||||||
|                 ADDOP(c, ROT_TWO); |                 ADDOP_I(c, SWAP, 2); | ||||||
|             } |             } | ||||||
|             ADDOP(c, POP_BLOCK); |             ADDOP(c, POP_BLOCK); | ||||||
|             ADDOP(c, POP_EXCEPT); |             ADDOP(c, POP_EXCEPT); | ||||||
|  | @ -1970,7 +1962,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, | ||||||
| 
 | 
 | ||||||
|         case POP_VALUE: |         case POP_VALUE: | ||||||
|             if (preserve_tos) { |             if (preserve_tos) { | ||||||
|                 ADDOP(c, ROT_TWO); |                 ADDOP_I(c, SWAP, 2); | ||||||
|             } |             } | ||||||
|             ADDOP(c, POP_TOP); |             ADDOP(c, POP_TOP); | ||||||
|             return 1; |             return 1; | ||||||
|  | @ -2647,7 +2639,7 @@ compiler_class(struct compiler *c, stmt_ty s) | ||||||
|             assert(i == 0); |             assert(i == 0); | ||||||
| 
 | 
 | ||||||
|             ADDOP_I(c, LOAD_CLOSURE, i); |             ADDOP_I(c, LOAD_CLOSURE, i); | ||||||
|             ADDOP(c, DUP_TOP); |             ADDOP_I(c, COPY, 1); | ||||||
|             str = PyUnicode_InternFromString("__classcell__"); |             str = PyUnicode_InternFromString("__classcell__"); | ||||||
|             if (!str || !compiler_nameop(c, str, Store)) { |             if (!str || !compiler_nameop(c, str, Store)) { | ||||||
|                 Py_XDECREF(str); |                 Py_XDECREF(str); | ||||||
|  | @ -2843,8 +2835,8 @@ compiler_jump_if(struct compiler *c, expr_ty e, basicblock *next, int cond) | ||||||
|             for (i = 0; i < n; i++) { |             for (i = 0; i < n; i++) { | ||||||
|                 VISIT(c, expr, |                 VISIT(c, expr, | ||||||
|                     (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); |                     (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); | ||||||
|                 ADDOP(c, DUP_TOP); |                 ADDOP_I(c, SWAP, 2); | ||||||
|                 ADDOP(c, ROT_THREE); |                 ADDOP_I(c, COPY, 2); | ||||||
|                 ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); |                 ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); | ||||||
|                 ADDOP_JUMP(c, POP_JUMP_IF_FALSE, cleanup); |                 ADDOP_JUMP(c, POP_JUMP_IF_FALSE, cleanup); | ||||||
|                 NEXT_BLOCK(c); |                 NEXT_BLOCK(c); | ||||||
|  | @ -3500,9 +3492,9 @@ compiler_try_except(struct compiler *c, stmt_ty s) | ||||||
|    []                                         POP_BLOCK |    []                                         POP_BLOCK | ||||||
|    []                                         JUMP_FORWARD          L0 |    []                                         JUMP_FORWARD          L0 | ||||||
| 
 | 
 | ||||||
|    [exc]                            L1:       DUP_TOP      )  save copy of the original exception |    [exc]                            L1:       COPY 1      )  save copy of the original exception | ||||||
|    [orig, exc]                                BUILD_LIST   )  list for raised/reraised excs ("result") |    [orig, exc]                                BUILD_LIST   )  list for raised/reraised excs ("result") | ||||||
|    [orig, exc, res]                           ROT_TWO |    [orig, exc, res]                           SWAP 2 | ||||||
| 
 | 
 | ||||||
|    [orig, res, exc]                           <evaluate E1> |    [orig, res, exc]                           <evaluate E1> | ||||||
|    [orig, res, exc, E1]                       JUMP_IF_NOT_EG_MATCH L2 |    [orig, res, exc, E1]                       JUMP_IF_NOT_EG_MATCH L2 | ||||||
|  | @ -3522,12 +3514,12 @@ compiler_try_except(struct compiler *c, stmt_ty s) | ||||||
|    [orig, res, rest]                Ln+1:     LIST_APPEND 1  ) add unhandled exc to res (could be None) |    [orig, res, rest]                Ln+1:     LIST_APPEND 1  ) add unhandled exc to res (could be None) | ||||||
| 
 | 
 | ||||||
|    [orig, res]                                PREP_RERAISE_STAR |    [orig, res]                                PREP_RERAISE_STAR | ||||||
|    [exc]                                      DUP_TOP |    [exc]                                      COPY 1 | ||||||
|    [exc, exc]                                 POP_JUMP_IF_NOT_NONE  RER |    [exc, exc]                                 POP_JUMP_IF_NOT_NONE  RER | ||||||
|    [exc]                                      POP_TOP |    [exc]                                      POP_TOP | ||||||
|    []                                         JUMP_FORWARD          L0 |    []                                         JUMP_FORWARD          L0 | ||||||
| 
 | 
 | ||||||
|    [exc]                            RER:      ROT_TWO |    [exc]                            RER:      SWAP 2 | ||||||
|    [exc, prev_exc_info]                       POP_EXCEPT |    [exc, prev_exc_info]                       POP_EXCEPT | ||||||
|    [exc]                                      RERAISE               0 |    [exc]                                      RERAISE               0 | ||||||
| 
 | 
 | ||||||
|  | @ -3592,19 +3584,19 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) | ||||||
|         if (i == 0) { |         if (i == 0) { | ||||||
|             /* Push the original EG into the stack */ |             /* Push the original EG into the stack */ | ||||||
|             /*
 |             /*
 | ||||||
|                [exc]            DUP_TOP |                [exc]            COPY 1 | ||||||
|                [orig, exc] |                [orig, exc] | ||||||
|             */ |             */ | ||||||
|             ADDOP(c, DUP_TOP); |             ADDOP_I(c, COPY, 1); | ||||||
| 
 | 
 | ||||||
|             /* create empty list for exceptions raised/reraise in the except* blocks */ |             /* create empty list for exceptions raised/reraise in the except* blocks */ | ||||||
|             /*
 |             /*
 | ||||||
|                [orig, exc]       BUILD_LIST |                [orig, exc]       BUILD_LIST | ||||||
|                [orig, exc, []]   ROT_TWO |                [orig, exc, []]   SWAP 2 | ||||||
|                [orig, [], exc] |                [orig, [], exc] | ||||||
|             */ |             */ | ||||||
|             ADDOP_I(c, BUILD_LIST, 0); |             ADDOP_I(c, BUILD_LIST, 0); | ||||||
|             ADDOP(c, ROT_TWO); |             ADDOP_I(c, SWAP, 2); | ||||||
|         } |         } | ||||||
|         if (handler->v.ExceptHandler.type) { |         if (handler->v.ExceptHandler.type) { | ||||||
|             VISIT(c, expr, handler->v.ExceptHandler.type); |             VISIT(c, expr, handler->v.ExceptHandler.type); | ||||||
|  | @ -3692,7 +3684,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) | ||||||
| 
 | 
 | ||||||
|     compiler_use_next_block(c, reraise_star); |     compiler_use_next_block(c, reraise_star); | ||||||
|     ADDOP(c, PREP_RERAISE_STAR); |     ADDOP(c, PREP_RERAISE_STAR); | ||||||
|     ADDOP(c, DUP_TOP); |     ADDOP_I(c, COPY, 1); | ||||||
|     ADDOP_JUMP(c, POP_JUMP_IF_NOT_NONE, reraise); |     ADDOP_JUMP(c, POP_JUMP_IF_NOT_NONE, reraise); | ||||||
|     NEXT_BLOCK(c); |     NEXT_BLOCK(c); | ||||||
| 
 | 
 | ||||||
|  | @ -3703,7 +3695,7 @@ compiler_try_star_except(struct compiler *c, stmt_ty s) | ||||||
|     ADDOP_JUMP(c, JUMP_FORWARD, end); |     ADDOP_JUMP(c, JUMP_FORWARD, end); | ||||||
|     compiler_use_next_block(c, reraise); |     compiler_use_next_block(c, reraise); | ||||||
|     ADDOP(c, POP_BLOCK); |     ADDOP(c, POP_BLOCK); | ||||||
|     ADDOP(c, ROT_TWO); |     ADDOP_I(c, SWAP, 2); | ||||||
|     ADDOP(c, POP_EXCEPT); |     ADDOP(c, POP_EXCEPT); | ||||||
|     ADDOP_I(c, RERAISE, 0); |     ADDOP_I(c, RERAISE, 0); | ||||||
|     compiler_use_next_block(c, cleanup); |     compiler_use_next_block(c, cleanup); | ||||||
|  | @ -3761,7 +3753,7 @@ compiler_import_as(struct compiler *c, identifier name, identifier asname) | ||||||
|             if (dot == -1) { |             if (dot == -1) { | ||||||
|                 break; |                 break; | ||||||
|             } |             } | ||||||
|             ADDOP(c, ROT_TWO); |             ADDOP_I(c, SWAP, 2); | ||||||
|             ADDOP(c, POP_TOP); |             ADDOP(c, POP_TOP); | ||||||
|         } |         } | ||||||
|         if (!compiler_nameop(c, asname, Store)) { |         if (!compiler_nameop(c, asname, Store)) { | ||||||
|  | @ -3961,8 +3953,9 @@ compiler_visit_stmt(struct compiler *c, stmt_ty s) | ||||||
|         n = asdl_seq_LEN(s->v.Assign.targets); |         n = asdl_seq_LEN(s->v.Assign.targets); | ||||||
|         VISIT(c, expr, s->v.Assign.value); |         VISIT(c, expr, s->v.Assign.value); | ||||||
|         for (i = 0; i < n; i++) { |         for (i = 0; i < n; i++) { | ||||||
|             if (i < n - 1) |             if (i < n - 1) { | ||||||
|                 ADDOP(c, DUP_TOP); |                 ADDOP_I(c, COPY, 1); | ||||||
|  |             } | ||||||
|             VISIT(c, expr, |             VISIT(c, expr, | ||||||
|                   (expr_ty)asdl_seq_GET(s->v.Assign.targets, i)); |                   (expr_ty)asdl_seq_GET(s->v.Assign.targets, i)); | ||||||
|         } |         } | ||||||
|  | @ -4532,8 +4525,8 @@ compiler_compare(struct compiler *c, expr_ty e) | ||||||
|         for (i = 0; i < n; i++) { |         for (i = 0; i < n; i++) { | ||||||
|             VISIT(c, expr, |             VISIT(c, expr, | ||||||
|                 (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); |                 (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i)); | ||||||
|             ADDOP(c, DUP_TOP); |             ADDOP_I(c, SWAP, 2); | ||||||
|             ADDOP(c, ROT_THREE); |             ADDOP_I(c, COPY, 2); | ||||||
|             ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); |             ADDOP_COMPARE(c, asdl_seq_GET(e->v.Compare.ops, i)); | ||||||
|             ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, cleanup); |             ADDOP_JUMP(c, JUMP_IF_FALSE_OR_POP, cleanup); | ||||||
|             NEXT_BLOCK(c); |             NEXT_BLOCK(c); | ||||||
|  | @ -4545,7 +4538,7 @@ compiler_compare(struct compiler *c, expr_ty e) | ||||||
|             return 0; |             return 0; | ||||||
|         ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); |         ADDOP_JUMP_NOLINE(c, JUMP_FORWARD, end); | ||||||
|         compiler_use_next_block(c, cleanup); |         compiler_use_next_block(c, cleanup); | ||||||
|         ADDOP(c, ROT_TWO); |         ADDOP_I(c, SWAP, 2); | ||||||
|         ADDOP(c, POP_TOP); |         ADDOP(c, POP_TOP); | ||||||
|         compiler_use_next_block(c, end); |         compiler_use_next_block(c, end); | ||||||
|     } |     } | ||||||
|  | @ -5689,7 +5682,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) | ||||||
|     switch (e->kind) { |     switch (e->kind) { | ||||||
|     case NamedExpr_kind: |     case NamedExpr_kind: | ||||||
|         VISIT(c, expr, e->v.NamedExpr.value); |         VISIT(c, expr, e->v.NamedExpr.value); | ||||||
|         ADDOP(c, DUP_TOP); |         ADDOP_I(c, COPY, 1); | ||||||
|         VISIT(c, expr, e->v.NamedExpr.target); |         VISIT(c, expr, e->v.NamedExpr.target); | ||||||
|         break; |         break; | ||||||
|     case BoolOp_kind: |     case BoolOp_kind: | ||||||
|  | @ -5854,7 +5847,7 @@ compiler_augassign(struct compiler *c, stmt_ty s) | ||||||
|     switch (e->kind) { |     switch (e->kind) { | ||||||
|     case Attribute_kind: |     case Attribute_kind: | ||||||
|         VISIT(c, expr, e->v.Attribute.value); |         VISIT(c, expr, e->v.Attribute.value); | ||||||
|         ADDOP(c, DUP_TOP); |         ADDOP_I(c, COPY, 1); | ||||||
|         int old_lineno = c->u->u_lineno; |         int old_lineno = c->u->u_lineno; | ||||||
|         c->u->u_lineno = e->end_lineno; |         c->u->u_lineno = e->end_lineno; | ||||||
|         ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names); |         ADDOP_NAME(c, LOAD_ATTR, e->v.Attribute.attr, names); | ||||||
|  | @ -5863,7 +5856,8 @@ compiler_augassign(struct compiler *c, stmt_ty s) | ||||||
|     case Subscript_kind: |     case Subscript_kind: | ||||||
|         VISIT(c, expr, e->v.Subscript.value); |         VISIT(c, expr, e->v.Subscript.value); | ||||||
|         VISIT(c, expr, e->v.Subscript.slice); |         VISIT(c, expr, e->v.Subscript.slice); | ||||||
|         ADDOP(c, DUP_TOP_TWO); |         ADDOP_I(c, COPY, 2); | ||||||
|  |         ADDOP_I(c, COPY, 2); | ||||||
|         ADDOP(c, BINARY_SUBSCR); |         ADDOP(c, BINARY_SUBSCR); | ||||||
|         break; |         break; | ||||||
|     case Name_kind: |     case Name_kind: | ||||||
|  | @ -5890,11 +5884,12 @@ compiler_augassign(struct compiler *c, stmt_ty s) | ||||||
|     switch (e->kind) { |     switch (e->kind) { | ||||||
|     case Attribute_kind: |     case Attribute_kind: | ||||||
|         c->u->u_lineno = e->end_lineno; |         c->u->u_lineno = e->end_lineno; | ||||||
|         ADDOP(c, ROT_TWO); |         ADDOP_I(c, SWAP, 2); | ||||||
|         ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); |         ADDOP_NAME(c, STORE_ATTR, e->v.Attribute.attr, names); | ||||||
|         break; |         break; | ||||||
|     case Subscript_kind: |     case Subscript_kind: | ||||||
|         ADDOP(c, ROT_THREE); |         ADDOP_I(c, SWAP, 3); | ||||||
|  |         ADDOP_I(c, SWAP, 2); | ||||||
|         ADDOP(c, STORE_SUBSCR); |         ADDOP(c, STORE_SUBSCR); | ||||||
|         break; |         break; | ||||||
|     case Name_kind: |     case Name_kind: | ||||||
|  | @ -6246,6 +6241,16 @@ compiler_error_duplicate_store(struct compiler *c, identifier n) | ||||||
|     return compiler_error(c, "multiple assignments to name %R in pattern", n); |     return compiler_error(c, "multiple assignments to name %R in pattern", n); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Duplicate the effect of 3.10's ROT_* instructions using SWAPs.
 | ||||||
|  | static int | ||||||
|  | pattern_helper_rotate(struct compiler *c, Py_ssize_t count) | ||||||
|  | { | ||||||
|  |     while (1 < count) { | ||||||
|  |         ADDOP_I(c, SWAP, count--); | ||||||
|  |     } | ||||||
|  |     return 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int | static int | ||||||
| pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) | pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) | ||||||
| { | { | ||||||
|  | @ -6265,7 +6270,8 @@ pattern_helper_store_name(struct compiler *c, identifier n, pattern_context *pc) | ||||||
|         return compiler_error_duplicate_store(c, n); |         return compiler_error_duplicate_store(c, n); | ||||||
|     } |     } | ||||||
|     // Rotate this object underneath any items we need to preserve:
 |     // Rotate this object underneath any items we need to preserve:
 | ||||||
|     ADDOP_I(c, ROT_N, pc->on_top + PyList_GET_SIZE(pc->stores) + 1); |     Py_ssize_t rotations = pc->on_top + PyList_GET_SIZE(pc->stores) + 1; | ||||||
|  |     RETURN_IF_FALSE(pattern_helper_rotate(c, rotations)); | ||||||
|     return !PyList_Append(pc->stores, n); |     return !PyList_Append(pc->stores, n); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -6334,7 +6340,7 @@ pattern_helper_sequence_subscr(struct compiler *c, asdl_pattern_seq *patterns, | ||||||
|             assert(WILDCARD_STAR_CHECK(pattern)); |             assert(WILDCARD_STAR_CHECK(pattern)); | ||||||
|             continue; |             continue; | ||||||
|         } |         } | ||||||
|         ADDOP(c, DUP_TOP); |         ADDOP_I(c, COPY, 1); | ||||||
|         if (i < star) { |         if (i < star) { | ||||||
|             ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); |             ADDOP_LOAD_CONST_NEW(c, PyLong_FromSsize_t(i)); | ||||||
|         } |         } | ||||||
|  | @ -6383,7 +6389,7 @@ compiler_pattern_as(struct compiler *c, pattern_ty p, pattern_context *pc) | ||||||
|     } |     } | ||||||
|     // Need to make a copy for (possibly) storing later:
 |     // Need to make a copy for (possibly) storing later:
 | ||||||
|     pc->on_top++; |     pc->on_top++; | ||||||
|     ADDOP(c, DUP_TOP); |     ADDOP_I(c, COPY, 1); | ||||||
|     RETURN_IF_FALSE(compiler_pattern(c, p->v.MatchAs.pattern, pc)); |     RETURN_IF_FALSE(compiler_pattern(c, p->v.MatchAs.pattern, pc)); | ||||||
|     // Success! Store it:
 |     // Success! Store it:
 | ||||||
|     pc->on_top--; |     pc->on_top--; | ||||||
|  | @ -6458,7 +6464,7 @@ compiler_pattern_class(struct compiler *c, pattern_ty p, pattern_context *pc) | ||||||
|     } |     } | ||||||
|     ADDOP_LOAD_CONST_NEW(c, attr_names); |     ADDOP_LOAD_CONST_NEW(c, attr_names); | ||||||
|     ADDOP_I(c, MATCH_CLASS, nargs); |     ADDOP_I(c, MATCH_CLASS, nargs); | ||||||
|     ADDOP(c, DUP_TOP); |     ADDOP_I(c, COPY, 1); | ||||||
|     ADDOP_LOAD_CONST(c, Py_None); |     ADDOP_LOAD_CONST(c, Py_None); | ||||||
|     ADDOP_I(c, IS_OP, 1); |     ADDOP_I(c, IS_OP, 1); | ||||||
|     // TOS is now a tuple of (nargs + nattrs) attributes (or None):
 |     // TOS is now a tuple of (nargs + nattrs) attributes (or None):
 | ||||||
|  | @ -6576,7 +6582,7 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) | ||||||
|     ADDOP(c, MATCH_KEYS); |     ADDOP(c, MATCH_KEYS); | ||||||
|     // There's now a tuple of keys and a tuple of values on top of the subject:
 |     // There's now a tuple of keys and a tuple of values on top of the subject:
 | ||||||
|     pc->on_top += 2; |     pc->on_top += 2; | ||||||
|     ADDOP(c, DUP_TOP); |     ADDOP_I(c, COPY, 1); | ||||||
|     ADDOP_LOAD_CONST(c, Py_None); |     ADDOP_LOAD_CONST(c, Py_None); | ||||||
|     ADDOP_I(c, IS_OP, 1); |     ADDOP_I(c, IS_OP, 1); | ||||||
|     RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); |     RETURN_IF_FALSE(jump_to_fail_pop(c, pc, POP_JUMP_IF_FALSE)); | ||||||
|  | @ -6600,13 +6606,12 @@ compiler_pattern_mapping(struct compiler *c, pattern_ty p, pattern_context *pc) | ||||||
|         // for key in TOS:
 |         // for key in TOS:
 | ||||||
|         //     del rest[key]
 |         //     del rest[key]
 | ||||||
|         ADDOP_I(c, BUILD_MAP, 0);           // [subject, keys, empty]
 |         ADDOP_I(c, BUILD_MAP, 0);           // [subject, keys, empty]
 | ||||||
|         ADDOP(c, ROT_THREE);                // [empty, subject, keys]
 |         ADDOP_I(c, SWAP, 3);                // [empty, keys, subject]
 | ||||||
|         ADDOP(c, ROT_TWO);                  // [empty, keys, subject]
 |  | ||||||
|         ADDOP_I(c, DICT_UPDATE, 2);         // [copy, keys]
 |         ADDOP_I(c, DICT_UPDATE, 2);         // [copy, keys]
 | ||||||
|         ADDOP_I(c, UNPACK_SEQUENCE, size);  // [copy, keys...]
 |         ADDOP_I(c, UNPACK_SEQUENCE, size);  // [copy, keys...]
 | ||||||
|         while (size) { |         while (size) { | ||||||
|             ADDOP_I(c, COPY, 1 + size--);   // [copy, keys..., copy]
 |             ADDOP_I(c, COPY, 1 + size--);   // [copy, keys..., copy]
 | ||||||
|             ADDOP(c, ROT_TWO);              // [copy, keys..., copy, key]
 |             ADDOP_I(c, SWAP, 2);            // [copy, keys..., copy, key]
 | ||||||
|             ADDOP(c, DELETE_SUBSCR);        // [copy, keys...]
 |             ADDOP(c, DELETE_SUBSCR);        // [copy, keys...]
 | ||||||
|         } |         } | ||||||
|         RETURN_IF_FALSE(pattern_helper_store_name(c, star_target, pc)); |         RETURN_IF_FALSE(pattern_helper_store_name(c, star_target, pc)); | ||||||
|  | @ -6651,7 +6656,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) | ||||||
|         pc->fail_pop = NULL; |         pc->fail_pop = NULL; | ||||||
|         pc->fail_pop_size = 0; |         pc->fail_pop_size = 0; | ||||||
|         pc->on_top = 0; |         pc->on_top = 0; | ||||||
|         if (!compiler_addop(c, DUP_TOP) || !compiler_pattern(c, alt, pc)) { |         if (!compiler_addop_i(c, COPY, 1) || !compiler_pattern(c, alt, pc)) { | ||||||
|             goto error; |             goto error; | ||||||
|         } |         } | ||||||
|         // Success!
 |         // Success!
 | ||||||
|  | @ -6683,7 +6688,8 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) | ||||||
|                     // this; the current solution is potentially very
 |                     // this; the current solution is potentially very
 | ||||||
|                     // inefficient when each alternative subpattern binds lots
 |                     // inefficient when each alternative subpattern binds lots
 | ||||||
|                     // of names in different orders. It's fine for reasonable
 |                     // of names in different orders. It's fine for reasonable
 | ||||||
|                     // cases, though.
 |                     // cases, though, and the peephole optimizer will ensure
 | ||||||
|  |                     // that the final code is as efficient as possible.
 | ||||||
|                     assert(istores < icontrol); |                     assert(istores < icontrol); | ||||||
|                     Py_ssize_t rotations = istores + 1; |                     Py_ssize_t rotations = istores + 1; | ||||||
|                     // Perform the same rotation on pc->stores:
 |                     // Perform the same rotation on pc->stores:
 | ||||||
|  | @ -6702,9 +6708,10 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) | ||||||
|                     // rotated = pc_stores[:rotations]
 |                     // rotated = pc_stores[:rotations]
 | ||||||
|                     // del pc_stores[:rotations]
 |                     // del pc_stores[:rotations]
 | ||||||
|                     // pc_stores[icontrol-istores:icontrol-istores] = rotated
 |                     // pc_stores[icontrol-istores:icontrol-istores] = rotated
 | ||||||
|                     // Do the same thing to the stack, using several ROT_Ns:
 |                     // Do the same thing to the stack, using several 
 | ||||||
|  |                     // rotations:
 | ||||||
|                     while (rotations--) { |                     while (rotations--) { | ||||||
|                         if (!compiler_addop_i(c, ROT_N, icontrol + 1)) { |                         if (!pattern_helper_rotate(c, icontrol + 1)){ | ||||||
|                             goto error; |                             goto error; | ||||||
|                         } |                         } | ||||||
|                     } |                     } | ||||||
|  | @ -6730,7 +6737,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) | ||||||
|     } |     } | ||||||
|     compiler_use_next_block(c, end); |     compiler_use_next_block(c, end); | ||||||
|     Py_ssize_t nstores = PyList_GET_SIZE(control); |     Py_ssize_t nstores = PyList_GET_SIZE(control); | ||||||
|     // There's a bunch of stuff on the stack between any where the new stores
 |     // There's a bunch of stuff on the stack between where the new stores
 | ||||||
|     // are and where they need to be:
 |     // are and where they need to be:
 | ||||||
|     // - The other stores.
 |     // - The other stores.
 | ||||||
|     // - A copy of the subject.
 |     // - A copy of the subject.
 | ||||||
|  | @ -6739,7 +6746,7 @@ compiler_pattern_or(struct compiler *c, pattern_ty p, pattern_context *pc) | ||||||
|     Py_ssize_t nrots = nstores + 1 + pc->on_top + PyList_GET_SIZE(pc->stores); |     Py_ssize_t nrots = nstores + 1 + pc->on_top + PyList_GET_SIZE(pc->stores); | ||||||
|     for (Py_ssize_t i = 0; i < nstores; i++) { |     for (Py_ssize_t i = 0; i < nstores; i++) { | ||||||
|         // Rotate this capture to its proper place on the stack:
 |         // Rotate this capture to its proper place on the stack:
 | ||||||
|         if (!compiler_addop_i(c, ROT_N, nrots)) { |         if (!pattern_helper_rotate(c, nrots)) { | ||||||
|             goto error; |             goto error; | ||||||
|         } |         } | ||||||
|         // Update the list of previous stores with this new name, checking for
 |         // Update the list of previous stores with this new name, checking for
 | ||||||
|  | @ -6898,7 +6905,7 @@ compiler_match_inner(struct compiler *c, stmt_ty s, pattern_context *pc) | ||||||
|         SET_LOC(c, m->pattern); |         SET_LOC(c, m->pattern); | ||||||
|         // Only copy the subject if we're *not* on the last case:
 |         // Only copy the subject if we're *not* on the last case:
 | ||||||
|         if (i != cases - has_default - 1) { |         if (i != cases - has_default - 1) { | ||||||
|             ADDOP(c, DUP_TOP); |             ADDOP_I(c, COPY, 1); | ||||||
|         } |         } | ||||||
|         RETURN_IF_FALSE(pc->stores = PyList_New(0)); |         RETURN_IF_FALSE(pc->stores = PyList_New(0)); | ||||||
|         // Irrefutable cases must be either guarded, last, or both:
 |         // Irrefutable cases must be either guarded, last, or both:
 | ||||||
|  | @ -8433,36 +8440,99 @@ fold_tuple_on_constants(struct compiler *c, | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #define VISITED (-1) | ||||||
| 
 | 
 | ||||||
| // Eliminate n * ROT_N(n).
 | // Replace an arbitrary run of SWAPs and NOPs with an optimal one that has the
 | ||||||
| static void | // same effect. Return the number of instructions that were optimized.
 | ||||||
| fold_rotations(struct instr *inst, int n) | static int | ||||||
|  | swaptimize(basicblock *block, int ix) | ||||||
| { | { | ||||||
|     for (int i = 0; i < n; i++) { |     // NOTE: "./python -m test test_patma" serves as a good, quick stress test
 | ||||||
|         int rot; |     // for this function. Make sure to blow away cached *.pyc files first!
 | ||||||
|         switch (inst[i].i_opcode) { |     assert(ix < block->b_iused); | ||||||
|             case ROT_N: |     struct instr *instructions = &block->b_instr[ix]; | ||||||
|                 rot = inst[i].i_oparg; |     // Find the length of the current sequence of SWAPs and NOPs, and record the
 | ||||||
|                 break; |     // maximum depth of the stack manipulations:
 | ||||||
|             case ROT_FOUR: |     assert(instructions[0].i_opcode == SWAP); | ||||||
|                 rot = 4; |     int depth = instructions[0].i_oparg; | ||||||
|                 break; |     int len = 0; | ||||||
|             case ROT_THREE: |     int more = false; | ||||||
|                 rot = 3; |     while (++len < block->b_iused - ix) { | ||||||
|                 break; |         int opcode = instructions[len].i_opcode; | ||||||
|             case ROT_TWO: |         if (opcode == SWAP) { | ||||||
|                 rot = 2; |             depth = Py_MAX(depth, instructions[len].i_oparg); | ||||||
|                 break; |             more = true; | ||||||
|             default: |  | ||||||
|                 return; |  | ||||||
|         } |         } | ||||||
|         if (rot != n) { |         else if (opcode != NOP) { | ||||||
|             return; |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     for (int i = 0; i < n; i++) { |     // It's already optimal if there's only one SWAP:
 | ||||||
|         inst[i].i_opcode = NOP; |     if (!more) { | ||||||
|  |         return 0; | ||||||
|     } |     } | ||||||
|  |     // Create an array with elements {0, 1, 2, ..., depth - 1}:
 | ||||||
|  |     int *stack = PyMem_Malloc(depth * sizeof(int)); | ||||||
|  |     for (int i = 0; i < depth; i++) { | ||||||
|  |         stack[i] = i; | ||||||
|  |     } | ||||||
|  |     // Simulate the combined effect of these instructions by "running" them on
 | ||||||
|  |     // our "stack":
 | ||||||
|  |     for (int i = 0; i < len; i++) { | ||||||
|  |         if (instructions[i].i_opcode == SWAP) { | ||||||
|  |             int oparg = instructions[i].i_oparg; | ||||||
|  |             int top = stack[0]; | ||||||
|  |             // SWAPs are 1-indexed:
 | ||||||
|  |             stack[0] = stack[oparg - 1]; | ||||||
|  |             stack[oparg - 1] = top; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // Now we can begin! Our approach here is based on a solution to a closely
 | ||||||
|  |     // related problem (https://cs.stackexchange.com/a/13938). It's easiest to
 | ||||||
|  |     // think of this algorithm as determining the steps needed to efficiently
 | ||||||
|  |     // "un-shuffle" our stack. By performing the moves in *reverse* order,
 | ||||||
|  |     // though, we can efficiently *shuffle* it! For this reason, we will be
 | ||||||
|  |     // replacing instructions starting from the *end* of the run. Since the
 | ||||||
|  |     // solution is optimal, we don't need to worry about running out of space:
 | ||||||
|  |     int current = len - 1; | ||||||
|  |     for (int i = 0; i < depth; i++) { | ||||||
|  |         // Skip items that have already been visited, or just happen to be in
 | ||||||
|  |         // the correct location:
 | ||||||
|  |         if (stack[i] == VISITED || stack[i] == i) { | ||||||
|  |             continue; | ||||||
|  |         } | ||||||
|  |         // Okay, we've found an item that hasn't been visited. It forms a cycle
 | ||||||
|  |         // with other items; traversing the cycle and swapping each item with
 | ||||||
|  |         // the next will put them all in the correct place. The weird
 | ||||||
|  |         // loop-and-a-half is necessary to insert 0 into every cycle, since we
 | ||||||
|  |         // can only swap from that position:
 | ||||||
|  |         int j = i; | ||||||
|  |         while (true) { | ||||||
|  |             // Skip the actual swap if our item is zero, since swapping the top
 | ||||||
|  |             // item with itself is pointless:
 | ||||||
|  |             if (j) { | ||||||
|  |                 assert(0 <= current); | ||||||
|  |                 // SWAPs are 1-indexed:
 | ||||||
|  |                 instructions[current].i_opcode = SWAP; | ||||||
|  |                 instructions[current--].i_oparg = j + 1; | ||||||
|  |             } | ||||||
|  |             if (stack[j] == VISITED) { | ||||||
|  |                 // Completed the cycle:
 | ||||||
|  |                 assert(j == i); | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |             int next_j = stack[j]; | ||||||
|  |             stack[j] = VISITED; | ||||||
|  |             j = next_j; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // NOP out any unused instructions:
 | ||||||
|  |     while (0 <= current) { | ||||||
|  |         instructions[current--].i_opcode = NOP; | ||||||
|  |     } | ||||||
|  |     // Done! Return the number of optimized instructions:
 | ||||||
|  |     PyMem_Free(stack); | ||||||
|  |     return len - 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Attempt to eliminate jumps to jumps by updating inst to jump to
 | // Attempt to eliminate jumps to jumps by updating inst to jump to
 | ||||||
|  | @ -8591,12 +8661,16 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) | ||||||
|                             bb->b_instr[i+1].i_opcode = NOP; |                             bb->b_instr[i+1].i_opcode = NOP; | ||||||
|                             break; |                             break; | ||||||
|                         case 2: |                         case 2: | ||||||
|                             inst->i_opcode = ROT_TWO; |                             inst->i_opcode = SWAP; | ||||||
|  |                             inst->i_oparg = 2; | ||||||
|                             bb->b_instr[i+1].i_opcode = NOP; |                             bb->b_instr[i+1].i_opcode = NOP; | ||||||
|  |                             i--; | ||||||
|                             break; |                             break; | ||||||
|                         case 3: |                         case 3: | ||||||
|                             inst->i_opcode = ROT_THREE; |                             inst->i_opcode = SWAP; | ||||||
|                             bb->b_instr[i+1].i_opcode = ROT_TWO; |                             inst->i_oparg = 3; | ||||||
|  |                             bb->b_instr[i+1].i_opcode = NOP; | ||||||
|  |                             i--; | ||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
|                 } |                 } | ||||||
|  | @ -8704,30 +8778,12 @@ optimize_basic_block(struct compiler *c, basicblock *bb, PyObject *consts) | ||||||
|                     i -= jump_thread(inst, target, FOR_ITER); |                     i -= jump_thread(inst, target, FOR_ITER); | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|             case ROT_N: |             case SWAP: | ||||||
|                 switch (oparg) { |  | ||||||
|                     case 0: |  | ||||||
|                     case 1: |  | ||||||
|                         inst->i_opcode = NOP; |  | ||||||
|                         continue; |  | ||||||
|                     case 2: |  | ||||||
|                         inst->i_opcode = ROT_TWO; |  | ||||||
|                         break; |  | ||||||
|                     case 3: |  | ||||||
|                         inst->i_opcode = ROT_THREE; |  | ||||||
|                         break; |  | ||||||
|                     case 4: |  | ||||||
|                         inst->i_opcode = ROT_FOUR; |  | ||||||
|                         break; |  | ||||||
|                 } |  | ||||||
|                 if (i >= oparg - 1) { |  | ||||||
|                     fold_rotations(inst - oparg + 1, oparg); |  | ||||||
|                 } |  | ||||||
|                 break; |  | ||||||
|             case COPY: |  | ||||||
|                 if (oparg == 1) { |                 if (oparg == 1) { | ||||||
|                     inst->i_opcode = DUP_TOP; |                     inst->i_opcode = NOP; | ||||||
|  |                     break; | ||||||
|                 } |                 } | ||||||
|  |                 i += swaptimize(bb, i); | ||||||
|                 break; |                 break; | ||||||
|             default: |             default: | ||||||
|                 /* All HAS_CONST opcodes should be handled with LOAD_CONST */ |                 /* All HAS_CONST opcodes should be handled with LOAD_CONST */ | ||||||
|  |  | ||||||
							
								
								
									
										76
									
								
								Python/opcode_targets.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										76
									
								
								Python/opcode_targets.h
									
										
									
										generated
									
									
									
								
							|  | @ -1,45 +1,40 @@ | ||||||
| static void *opcode_targets[256] = { | static void *opcode_targets[256] = { | ||||||
|     &&_unknown_opcode, |     &&_unknown_opcode, | ||||||
|     &&TARGET_POP_TOP, |     &&TARGET_POP_TOP, | ||||||
|     &&TARGET_ROT_TWO, |  | ||||||
|     &&TARGET_ROT_THREE, |  | ||||||
|     &&TARGET_DUP_TOP, |  | ||||||
|     &&TARGET_DUP_TOP_TWO, |  | ||||||
|     &&TARGET_ROT_FOUR, |  | ||||||
|     &&TARGET_BINARY_OP_ADAPTIVE, |     &&TARGET_BINARY_OP_ADAPTIVE, | ||||||
|     &&TARGET_BINARY_OP_ADD_INT, |     &&TARGET_BINARY_OP_ADD_INT, | ||||||
|  |     &&TARGET_BINARY_OP_ADD_FLOAT, | ||||||
|  |     &&TARGET_BINARY_OP_ADD_UNICODE, | ||||||
|  |     &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, | ||||||
|  |     &&TARGET_BINARY_OP_MULTIPLY_INT, | ||||||
|  |     &&TARGET_BINARY_OP_MULTIPLY_FLOAT, | ||||||
|     &&TARGET_NOP, |     &&TARGET_NOP, | ||||||
|     &&TARGET_UNARY_POSITIVE, |     &&TARGET_UNARY_POSITIVE, | ||||||
|     &&TARGET_UNARY_NEGATIVE, |     &&TARGET_UNARY_NEGATIVE, | ||||||
|     &&TARGET_UNARY_NOT, |     &&TARGET_UNARY_NOT, | ||||||
|     &&TARGET_BINARY_OP_ADD_FLOAT, |  | ||||||
|     &&TARGET_BINARY_OP_ADD_UNICODE, |  | ||||||
|     &&TARGET_UNARY_INVERT, |  | ||||||
|     &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE, |  | ||||||
|     &&TARGET_BINARY_OP_MULTIPLY_INT, |  | ||||||
|     &&TARGET_BINARY_OP_MULTIPLY_FLOAT, |  | ||||||
|     &&TARGET_BINARY_OP_SUBTRACT_INT, |     &&TARGET_BINARY_OP_SUBTRACT_INT, | ||||||
|     &&TARGET_BINARY_OP_SUBTRACT_FLOAT, |     &&TARGET_BINARY_OP_SUBTRACT_FLOAT, | ||||||
|  |     &&TARGET_UNARY_INVERT, | ||||||
|     &&TARGET_COMPARE_OP_ADAPTIVE, |     &&TARGET_COMPARE_OP_ADAPTIVE, | ||||||
|     &&TARGET_COMPARE_OP_FLOAT_JUMP, |     &&TARGET_COMPARE_OP_FLOAT_JUMP, | ||||||
|     &&TARGET_COMPARE_OP_INT_JUMP, |     &&TARGET_COMPARE_OP_INT_JUMP, | ||||||
|     &&TARGET_COMPARE_OP_STR_JUMP, |     &&TARGET_COMPARE_OP_STR_JUMP, | ||||||
|     &&TARGET_BINARY_SUBSCR, |  | ||||||
|     &&TARGET_BINARY_SUBSCR_ADAPTIVE, |     &&TARGET_BINARY_SUBSCR_ADAPTIVE, | ||||||
|     &&TARGET_BINARY_SUBSCR_GETITEM, |     &&TARGET_BINARY_SUBSCR_GETITEM, | ||||||
|     &&TARGET_BINARY_SUBSCR_LIST_INT, |     &&TARGET_BINARY_SUBSCR_LIST_INT, | ||||||
|     &&TARGET_BINARY_SUBSCR_TUPLE_INT, |     &&TARGET_BINARY_SUBSCR_TUPLE_INT, | ||||||
|     &&TARGET_GET_LEN, |  | ||||||
|     &&TARGET_MATCH_MAPPING, |  | ||||||
|     &&TARGET_MATCH_SEQUENCE, |  | ||||||
|     &&TARGET_MATCH_KEYS, |  | ||||||
|     &&TARGET_BINARY_SUBSCR_DICT, |     &&TARGET_BINARY_SUBSCR_DICT, | ||||||
|     &&TARGET_PUSH_EXC_INFO, |     &&TARGET_BINARY_SUBSCR, | ||||||
|     &&TARGET_STORE_SUBSCR_ADAPTIVE, |     &&TARGET_STORE_SUBSCR_ADAPTIVE, | ||||||
|     &&TARGET_STORE_SUBSCR_LIST_INT, |     &&TARGET_STORE_SUBSCR_LIST_INT, | ||||||
|     &&TARGET_STORE_SUBSCR_DICT, |     &&TARGET_STORE_SUBSCR_DICT, | ||||||
|     &&TARGET_CALL_NO_KW_ADAPTIVE, |     &&TARGET_CALL_NO_KW_ADAPTIVE, | ||||||
|  |     &&TARGET_GET_LEN, | ||||||
|  |     &&TARGET_MATCH_MAPPING, | ||||||
|  |     &&TARGET_MATCH_SEQUENCE, | ||||||
|  |     &&TARGET_MATCH_KEYS, | ||||||
|     &&TARGET_CALL_NO_KW_BUILTIN_O, |     &&TARGET_CALL_NO_KW_BUILTIN_O, | ||||||
|  |     &&TARGET_PUSH_EXC_INFO, | ||||||
|     &&TARGET_CALL_NO_KW_BUILTIN_FAST, |     &&TARGET_CALL_NO_KW_BUILTIN_FAST, | ||||||
|     &&TARGET_CALL_NO_KW_LEN, |     &&TARGET_CALL_NO_KW_LEN, | ||||||
|     &&TARGET_CALL_NO_KW_ISINSTANCE, |     &&TARGET_CALL_NO_KW_ISINSTANCE, | ||||||
|  | @ -48,39 +43,44 @@ static void *opcode_targets[256] = { | ||||||
|     &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, |     &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, | ||||||
|     &&TARGET_CALL_NO_KW_TYPE_1, |     &&TARGET_CALL_NO_KW_TYPE_1, | ||||||
|     &&TARGET_CALL_NO_KW_BUILTIN_CLASS_1, |     &&TARGET_CALL_NO_KW_BUILTIN_CLASS_1, | ||||||
|  |     &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, | ||||||
|  |     &&TARGET_JUMP_ABSOLUTE_QUICK, | ||||||
|  |     &&TARGET_LOAD_ATTR_ADAPTIVE, | ||||||
|  |     &&TARGET_LOAD_ATTR_INSTANCE_VALUE, | ||||||
|  |     &&TARGET_LOAD_ATTR_WITH_HINT, | ||||||
|     &&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_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, |  | ||||||
|     &&TARGET_JUMP_ABSOLUTE_QUICK, |  | ||||||
|     &&TARGET_LOAD_ATTR_ADAPTIVE, |  | ||||||
|     &&TARGET_LOAD_ATTR_INSTANCE_VALUE, |  | ||||||
|     &&TARGET_LOAD_ATTR_WITH_HINT, |  | ||||||
|     &&TARGET_STORE_SUBSCR, |  | ||||||
|     &&TARGET_DELETE_SUBSCR, |  | ||||||
|     &&TARGET_LOAD_ATTR_SLOT, |     &&TARGET_LOAD_ATTR_SLOT, | ||||||
|     &&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_LOAD_GLOBAL_BUILTIN, |     &&TARGET_LOAD_GLOBAL_BUILTIN, | ||||||
|  |     &&TARGET_STORE_SUBSCR, | ||||||
|  |     &&TARGET_DELETE_SUBSCR, | ||||||
|     &&TARGET_LOAD_METHOD_ADAPTIVE, |     &&TARGET_LOAD_METHOD_ADAPTIVE, | ||||||
|     &&TARGET_GET_ITER, |  | ||||||
|     &&TARGET_GET_YIELD_FROM_ITER, |  | ||||||
|     &&TARGET_PRINT_EXPR, |  | ||||||
|     &&TARGET_LOAD_BUILD_CLASS, |  | ||||||
|     &&TARGET_LOAD_METHOD_CACHED, |     &&TARGET_LOAD_METHOD_CACHED, | ||||||
|     &&TARGET_GET_AWAITABLE, |  | ||||||
|     &&TARGET_LOAD_ASSERTION_ERROR, |  | ||||||
|     &&TARGET_RETURN_GENERATOR, |  | ||||||
|     &&TARGET_LOAD_METHOD_CLASS, |     &&TARGET_LOAD_METHOD_CLASS, | ||||||
|     &&TARGET_LOAD_METHOD_MODULE, |     &&TARGET_LOAD_METHOD_MODULE, | ||||||
|     &&TARGET_LOAD_METHOD_NO_DICT, |     &&TARGET_LOAD_METHOD_NO_DICT, | ||||||
|     &&TARGET_STORE_ATTR_ADAPTIVE, |     &&TARGET_STORE_ATTR_ADAPTIVE, | ||||||
|  |     &&TARGET_GET_ITER, | ||||||
|  |     &&TARGET_GET_YIELD_FROM_ITER, | ||||||
|  |     &&TARGET_PRINT_EXPR, | ||||||
|  |     &&TARGET_LOAD_BUILD_CLASS, | ||||||
|     &&TARGET_STORE_ATTR_INSTANCE_VALUE, |     &&TARGET_STORE_ATTR_INSTANCE_VALUE, | ||||||
|  |     &&TARGET_GET_AWAITABLE, | ||||||
|  |     &&TARGET_LOAD_ASSERTION_ERROR, | ||||||
|  |     &&TARGET_RETURN_GENERATOR, | ||||||
|     &&TARGET_STORE_ATTR_SLOT, |     &&TARGET_STORE_ATTR_SLOT, | ||||||
|  |     &&TARGET_STORE_ATTR_WITH_HINT, | ||||||
|  |     &&TARGET_LOAD_FAST__LOAD_FAST, | ||||||
|  |     &&TARGET_STORE_FAST__LOAD_FAST, | ||||||
|  |     &&TARGET_LOAD_FAST__LOAD_CONST, | ||||||
|  |     &&TARGET_LOAD_CONST__LOAD_FAST, | ||||||
|     &&TARGET_LIST_TO_TUPLE, |     &&TARGET_LIST_TO_TUPLE, | ||||||
|     &&TARGET_RETURN_VALUE, |     &&TARGET_RETURN_VALUE, | ||||||
|     &&TARGET_IMPORT_STAR, |     &&TARGET_IMPORT_STAR, | ||||||
|  | @ -98,7 +98,7 @@ static void *opcode_targets[256] = { | ||||||
|     &&TARGET_DELETE_ATTR, |     &&TARGET_DELETE_ATTR, | ||||||
|     &&TARGET_STORE_GLOBAL, |     &&TARGET_STORE_GLOBAL, | ||||||
|     &&TARGET_DELETE_GLOBAL, |     &&TARGET_DELETE_GLOBAL, | ||||||
|     &&TARGET_ROT_N, |     &&TARGET_SWAP, | ||||||
|     &&TARGET_LOAD_CONST, |     &&TARGET_LOAD_CONST, | ||||||
|     &&TARGET_LOAD_NAME, |     &&TARGET_LOAD_NAME, | ||||||
|     &&TARGET_BUILD_TUPLE, |     &&TARGET_BUILD_TUPLE, | ||||||
|  | @ -130,7 +130,7 @@ static void *opcode_targets[256] = { | ||||||
|     &&TARGET_POP_JUMP_IF_NOT_NONE, |     &&TARGET_POP_JUMP_IF_NOT_NONE, | ||||||
|     &&TARGET_POP_JUMP_IF_NONE, |     &&TARGET_POP_JUMP_IF_NONE, | ||||||
|     &&TARGET_RAISE_VARARGS, |     &&TARGET_RAISE_VARARGS, | ||||||
|     &&TARGET_STORE_ATTR_WITH_HINT, |     &&TARGET_STORE_FAST__STORE_FAST, | ||||||
|     &&TARGET_MAKE_FUNCTION, |     &&TARGET_MAKE_FUNCTION, | ||||||
|     &&TARGET_BUILD_SLICE, |     &&TARGET_BUILD_SLICE, | ||||||
|     &&TARGET_JUMP_NO_INTERRUPT, |     &&TARGET_JUMP_NO_INTERRUPT, | ||||||
|  | @ -139,20 +139,20 @@ static void *opcode_targets[256] = { | ||||||
|     &&TARGET_LOAD_DEREF, |     &&TARGET_LOAD_DEREF, | ||||||
|     &&TARGET_STORE_DEREF, |     &&TARGET_STORE_DEREF, | ||||||
|     &&TARGET_DELETE_DEREF, |     &&TARGET_DELETE_DEREF, | ||||||
|     &&TARGET_LOAD_FAST__LOAD_FAST, |     &&_unknown_opcode, | ||||||
|     &&TARGET_STORE_FAST__LOAD_FAST, |     &&_unknown_opcode, | ||||||
|     &&TARGET_CALL_FUNCTION_EX, |     &&TARGET_CALL_FUNCTION_EX, | ||||||
|     &&TARGET_LOAD_FAST__LOAD_CONST, |     &&_unknown_opcode, | ||||||
|     &&TARGET_EXTENDED_ARG, |     &&TARGET_EXTENDED_ARG, | ||||||
|     &&TARGET_LIST_APPEND, |     &&TARGET_LIST_APPEND, | ||||||
|     &&TARGET_SET_ADD, |     &&TARGET_SET_ADD, | ||||||
|     &&TARGET_MAP_ADD, |     &&TARGET_MAP_ADD, | ||||||
|     &&TARGET_LOAD_CLASSDEREF, |     &&TARGET_LOAD_CLASSDEREF, | ||||||
|     &&TARGET_COPY_FREE_VARS, |     &&TARGET_COPY_FREE_VARS, | ||||||
|     &&TARGET_LOAD_CONST__LOAD_FAST, |     &&_unknown_opcode, | ||||||
|     &&TARGET_RESUME, |     &&TARGET_RESUME, | ||||||
|     &&TARGET_MATCH_CLASS, |     &&TARGET_MATCH_CLASS, | ||||||
|     &&TARGET_STORE_FAST__STORE_FAST, |     &&_unknown_opcode, | ||||||
|     &&_unknown_opcode, |     &&_unknown_opcode, | ||||||
|     &&TARGET_FORMAT_VALUE, |     &&TARGET_FORMAT_VALUE, | ||||||
|     &&TARGET_BUILD_CONST_KEY_MAP, |     &&TARGET_BUILD_CONST_KEY_MAP, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Brandt Bucher
						Brandt Bucher