mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	bpo-45923: Handle call events in bytecode (GH-30364)
* Add a RESUME instruction to handle "call" events.
This commit is contained in:
		
							parent
							
								
									3e43fac250
								
							
						
					
					
						commit
						e028ae99ec
					
				
					 13 changed files with 672 additions and 523 deletions
				
			
		|  | @ -1206,6 +1206,20 @@ All of the following opcodes use their arguments. | |||
|    .. versionadded:: 3.11 | ||||
| 
 | ||||
| 
 | ||||
| .. opcode:: RESUME (where) | ||||
| 
 | ||||
|     A no-op. Performs internal tracing, debugging and optimization checks. | ||||
| 
 | ||||
|     The ``where`` operand marks where the ``RESUME`` occurs: | ||||
| 
 | ||||
|     * ``0`` The start of a function | ||||
|     * ``1`` After a ``yield`` expression | ||||
|     * ``2`` After a ``yield from`` expression | ||||
|     * ``3`` After an ``await`` expression | ||||
| 
 | ||||
|    .. versionadded:: 3.11 | ||||
| 
 | ||||
| 
 | ||||
| .. opcode:: HAVE_ARGUMENT | ||||
| 
 | ||||
|    This is not really an opcode.  It identifies the dividing line between | ||||
|  |  | |||
							
								
								
									
										1
									
								
								Include/opcode.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Include/opcode.h
									
										
									
										generated
									
									
									
								
							|  | @ -101,6 +101,7 @@ extern "C" { | |||
| #define MAP_ADD                         147 | ||||
| #define LOAD_CLASSDEREF                 148 | ||||
| #define COPY_FREE_VARS                  149 | ||||
| #define RESUME                          151 | ||||
| #define MATCH_CLASS                     152 | ||||
| #define FORMAT_VALUE                    155 | ||||
| #define BUILD_CONST_KEY_MAP             156 | ||||
|  |  | |||
|  | @ -379,16 +379,21 @@ def _write_atomic(path, data, mode=0o666): | |||
| #     Python 3.11a4 3471 (bpo-46202: remove pop POP_EXCEPT_AND_RERAISE) | ||||
| #     Python 3.11a4 3472 (bpo-46009: replace GEN_START with POP_TOP) | ||||
| #     Python 3.11a4 3473 (Add POP_JUMP_IF_NOT_NONE/POP_JUMP_IF_NONE opcodes) | ||||
| #     Python 3.11a4 3474 (Add RESUME opcode) | ||||
| 
 | ||||
| #     Python 3.12 will start with magic number 3500 | ||||
| 
 | ||||
| # | ||||
| # MAGIC must change whenever the bytecode emitted by the compiler may no | ||||
| # longer be understood by older implementations of the eval loop (usually | ||||
| # due to the addition of new opcodes). | ||||
| # | ||||
| # Starting with Python 3.11, Python 3.n starts with magic number 2900+50n. | ||||
| # | ||||
| # Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array | ||||
| # in PC/launcher.c must also be updated. | ||||
| 
 | ||||
| MAGIC_NUMBER = (3473).to_bytes(2, 'little') + b'\r\n' | ||||
| MAGIC_NUMBER = (3474).to_bytes(2, 'little') + b'\r\n' | ||||
| _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little')  # For import.c | ||||
| 
 | ||||
| _PYCACHE = '__pycache__' | ||||
|  |  | |||
|  | @ -178,6 +178,7 @@ def jabs_op(name, op): | |||
| hasfree.append(148) | ||||
| def_op('COPY_FREE_VARS', 149) | ||||
| 
 | ||||
| def_op('RESUME', 151) | ||||
| def_op('MATCH_CLASS', 152) | ||||
| 
 | ||||
| def_op('FORMAT_VALUE', 155) | ||||
|  |  | |||
|  | @ -367,7 +367,7 @@ def test_co_positions_artificial_instructions(self): | |||
|             # get assigned the first_lineno but they don't have other positions. | ||||
|             # There is no easy way of inferring them at that stage, so for now | ||||
|             # we don't support it. | ||||
|             self.assertTrue(positions.count(None) in [0, 4]) | ||||
|             self.assertIn(positions.count(None), [0, 3, 4]) | ||||
| 
 | ||||
|             if not any(positions): | ||||
|                 artificial_instructions.append(instr) | ||||
|  | @ -378,6 +378,7 @@ def test_co_positions_artificial_instructions(self): | |||
|                 for instruction in artificial_instructions | ||||
|             ], | ||||
|             [ | ||||
|                 ('RESUME', 0), | ||||
|                 ("PUSH_EXC_INFO", None), | ||||
|                 ("LOAD_CONST", None), # artificial 'None' | ||||
|                 ("STORE_NAME", "e"),  # XX: we know the location for this | ||||
|  | @ -419,7 +420,9 @@ def test_co_positions_empty_linetable(self): | |||
|         def func(): | ||||
|             x = 1 | ||||
|         new_code = func.__code__.replace(co_linetable=b'') | ||||
|         for line, end_line, column, end_column in new_code.co_positions(): | ||||
|         positions = new_code.co_positions() | ||||
|         next(positions) # Skip RESUME at start | ||||
|         for line, end_line, column, end_column in positions: | ||||
|             self.assertIsNone(line) | ||||
|             self.assertEqual(end_line, new_code.co_firstlineno + 1) | ||||
| 
 | ||||
|  | @ -428,7 +431,9 @@ def test_co_positions_empty_endlinetable(self): | |||
|         def func(): | ||||
|             x = 1 | ||||
|         new_code = func.__code__.replace(co_endlinetable=b'') | ||||
|         for line, end_line, column, end_column in new_code.co_positions(): | ||||
|         positions = new_code.co_positions() | ||||
|         next(positions) # Skip RESUME at start | ||||
|         for line, end_line, column, end_column in positions: | ||||
|             self.assertEqual(line, new_code.co_firstlineno + 1) | ||||
|             self.assertIsNone(end_line) | ||||
| 
 | ||||
|  | @ -437,7 +442,9 @@ def test_co_positions_empty_columntable(self): | |||
|         def func(): | ||||
|             x = 1 | ||||
|         new_code = func.__code__.replace(co_columntable=b'') | ||||
|         for line, end_line, column, end_column in new_code.co_positions(): | ||||
|         positions = new_code.co_positions() | ||||
|         next(positions) # Skip RESUME at start | ||||
|         for line, end_line, column, end_column in positions: | ||||
|             self.assertEqual(line, new_code.co_firstlineno + 1) | ||||
|             self.assertEqual(end_line, new_code.co_firstlineno + 1) | ||||
|             self.assertIsNone(column) | ||||
|  |  | |||
|  | @ -158,7 +158,7 @@ def test_leading_newlines(self): | |||
|         s256 = "".join(["\n"] * 256 + ["spam"]) | ||||
|         co = compile(s256, 'fn', 'exec') | ||||
|         self.assertEqual(co.co_firstlineno, 1) | ||||
|         self.assertEqual(list(co.co_lines()), [(0, 8, 257)]) | ||||
|         self.assertEqual(list(co.co_lines()), [(0, 2, None), (2, 10, 257)]) | ||||
| 
 | ||||
|     def test_literals_with_leading_zeroes(self): | ||||
|         for arg in ["077787", "0xj", "0x.", "0e",  "090000000000000", | ||||
|  | @ -759,7 +759,7 @@ def unused_block_while_else(): | |||
| 
 | ||||
|         for func in funcs: | ||||
|             opcodes = list(dis.get_instructions(func)) | ||||
|             self.assertLessEqual(len(opcodes), 3) | ||||
|             self.assertLessEqual(len(opcodes), 4) | ||||
|             self.assertEqual('LOAD_CONST', opcodes[-2].opname) | ||||
|             self.assertEqual(None, opcodes[-2].argval) | ||||
|             self.assertEqual('RETURN_VALUE', opcodes[-1].opname) | ||||
|  | @ -778,10 +778,10 @@ def continue_in_while(): | |||
|         # Check that we did not raise but we also don't generate bytecode | ||||
|         for func in funcs: | ||||
|             opcodes = list(dis.get_instructions(func)) | ||||
|             self.assertEqual(2, len(opcodes)) | ||||
|             self.assertEqual('LOAD_CONST', opcodes[0].opname) | ||||
|             self.assertEqual(None, opcodes[0].argval) | ||||
|             self.assertEqual('RETURN_VALUE', opcodes[1].opname) | ||||
|             self.assertEqual(3, len(opcodes)) | ||||
|             self.assertEqual('LOAD_CONST', opcodes[1].opname) | ||||
|             self.assertEqual(None, opcodes[1].argval) | ||||
|             self.assertEqual('RETURN_VALUE', opcodes[2].opname) | ||||
| 
 | ||||
|     def test_consts_in_conditionals(self): | ||||
|         def and_true(x): | ||||
|  | @ -802,9 +802,9 @@ def or_false(x): | |||
|         for func in funcs: | ||||
|             with self.subTest(func=func): | ||||
|                 opcodes = list(dis.get_instructions(func)) | ||||
|                 self.assertEqual(2, len(opcodes)) | ||||
|                 self.assertIn('LOAD_', opcodes[0].opname) | ||||
|                 self.assertEqual('RETURN_VALUE', opcodes[1].opname) | ||||
|                 self.assertLessEqual(len(opcodes), 3) | ||||
|                 self.assertIn('LOAD_', opcodes[-2].opname) | ||||
|                 self.assertEqual('RETURN_VALUE', opcodes[-1].opname) | ||||
| 
 | ||||
|     def test_imported_load_method(self): | ||||
|         sources = [ | ||||
|  | @ -906,7 +906,7 @@ def load_attr(): | |||
|                 o. | ||||
|                 a | ||||
|             ) | ||||
|         load_attr_lines = [ 2, 3, 1 ] | ||||
|         load_attr_lines = [ 0, 2, 3, 1 ] | ||||
| 
 | ||||
|         def load_method(): | ||||
|             return ( | ||||
|  | @ -915,7 +915,7 @@ def load_method(): | |||
|                     0 | ||||
|                 ) | ||||
|             ) | ||||
|         load_method_lines = [ 2, 3, 4, 3, 1 ] | ||||
|         load_method_lines = [ 0, 2, 3, 4, 3, 1 ] | ||||
| 
 | ||||
|         def store_attr(): | ||||
|             ( | ||||
|  | @ -924,7 +924,7 @@ def store_attr(): | |||
|             ) = ( | ||||
|                 v | ||||
|             ) | ||||
|         store_attr_lines = [ 5, 2, 3 ] | ||||
|         store_attr_lines = [ 0, 5, 2, 3 ] | ||||
| 
 | ||||
|         def aug_store_attr(): | ||||
|             ( | ||||
|  | @ -933,7 +933,7 @@ def aug_store_attr(): | |||
|             ) += ( | ||||
|                 v | ||||
|             ) | ||||
|         aug_store_attr_lines = [ 2, 3, 5, 1, 3 ] | ||||
|         aug_store_attr_lines = [ 0, 2, 3, 5, 1, 3 ] | ||||
| 
 | ||||
|         funcs = [ load_attr, load_method, store_attr, aug_store_attr] | ||||
|         func_lines = [ load_attr_lines, load_method_lines, | ||||
|  | @ -942,7 +942,8 @@ def aug_store_attr(): | |||
|         for func, lines in zip(funcs, func_lines, strict=True): | ||||
|             with self.subTest(func=func): | ||||
|                 code_lines = [ line-func.__code__.co_firstlineno | ||||
|                               for (_, _, line) in func.__code__.co_lines() ] | ||||
|                               for (_, _, line) in func.__code__.co_lines() | ||||
|                               if line is not None ] | ||||
|                 self.assertEqual(lines, code_lines) | ||||
| 
 | ||||
|     def test_line_number_genexp(self): | ||||
|  | @ -966,7 +967,7 @@ async def test(aseq): | |||
|             async for i in aseq: | ||||
|                 body | ||||
| 
 | ||||
|         expected_lines = [None, 1, 2, 1] | ||||
|         expected_lines = [None, 0, 1, 2, 1] | ||||
|         code_lines = [ None if line is None else line-test.__code__.co_firstlineno | ||||
|                       for (_, _, line) in test.__code__.co_lines() ] | ||||
|         self.assertEqual(expected_lines, code_lines) | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -0,0 +1,3 @@ | |||
| Add RESUME opcode. This is a logical no-op. It is emitted by the compiler | ||||
| anywhere a Python function can be entered. It is used by the interpreter to | ||||
| perform tracing and optimizer checks. | ||||
|  | @ -1268,7 +1268,9 @@ static PYC_MAGIC magic_values[] = { | |||
|     { 3400, 3419, L"3.8" }, | ||||
|     { 3420, 3429, L"3.9" }, | ||||
|     { 3430, 3449, L"3.10" }, | ||||
|     { 3450, 3469, L"3.11" }, | ||||
|     /* Allow 50 magic numbers per version from here on */ | ||||
|     { 3450, 3499, L"3.11" }, | ||||
|     { 3500, 3549, L"3.12" }, | ||||
|     { 0 } | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										62
									
								
								Programs/test_frozenmain.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										62
									
								
								Programs/test_frozenmain.h
									
										
									
										generated
									
									
									
								
							|  | @ -1,35 +1,35 @@ | |||
| // Auto-generated by Programs/freeze_test_frozenmain.py
 | ||||
| unsigned char M_test_frozenmain[] = { | ||||
|     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, | ||||
|     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,169,2,1,0,101,1, | ||||
|     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, | ||||
|     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, | ||||
|     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, | ||||
|     90,12,112,114,111,103,114,97,109,95,110,97,109,101,218,10, | ||||
|     101,120,101,99,117,116,97,98,108,101,90,15,117,115,101,95, | ||||
|     101,110,118,105,114,111,110,109,101,110,116,90,17,99,111,110, | ||||
|     102,105,103,117,114,101,95,99,95,115,116,100,105,111,90,14, | ||||
|     98,117,102,102,101,114,101,100,95,115,116,100,105,111,122,7, | ||||
|     99,111,110,102,105,103,32,122,2,58,32,41,7,218,3,115, | ||||
|     121,115,90,17,95,116,101,115,116,105,110,116,101,114,110,97, | ||||
|     108,99,97,112,105,218,5,112,114,105,110,116,218,4,97,114, | ||||
|     103,118,90,11,103,101,116,95,99,111,110,102,105,103,115,114, | ||||
|     2,0,0,0,218,3,107,101,121,169,0,243,0,0,0,0, | ||||
|     250,18,116,101,115,116,95,102,114,111,122,101,110,109,97,105, | ||||
|     110,46,112,121,218,8,60,109,111,100,117,108,101,62,114,11, | ||||
|     0,0,0,1,0,0,0,115,16,0,0,0,8,3,8,1, | ||||
|     8,2,12,1,12,1,8,1,26,7,4,249,115,18,0,0, | ||||
|     0,8,3,8,1,8,2,12,1,12,1,2,7,4,1,2, | ||||
|     249,30,7,115,86,0,0,0,1,11,1,11,1,11,1,11, | ||||
|     1,25,1,25,1,25,1,25,1,6,7,27,1,28,1,28, | ||||
|     1,6,7,17,19,22,19,27,1,28,1,28,10,27,10,39, | ||||
|     10,41,42,50,10,51,1,7,12,2,1,42,1,42,5,8, | ||||
|     5,10,11,41,21,24,11,41,11,41,28,34,35,38,28,39, | ||||
|     11,41,11,41,5,42,5,42,5,42,1,42,1,42,114,9, | ||||
|     0,0,0, | ||||
|     0,0,0,0,0,115,88,0,0,0,151,0,100,0,100,1, | ||||
|     108,0,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,169,2,1,0, | ||||
|     101,1,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,25,0,155,0,157,4,169,1,1,0,113,27,100,1, | ||||
|     83,0,41,8,233,0,0,0,0,78,122,18,70,114,111,122, | ||||
|     101,110,32,72,101,108,108,111,32,87,111,114,108,100,122,8, | ||||
|     115,121,115,46,97,114,103,118,218,6,99,111,110,102,105,103, | ||||
|     41,5,90,12,112,114,111,103,114,97,109,95,110,97,109,101, | ||||
|     218,10,101,120,101,99,117,116,97,98,108,101,90,15,117,115, | ||||
|     101,95,101,110,118,105,114,111,110,109,101,110,116,90,17,99, | ||||
|     111,110,102,105,103,117,114,101,95,99,95,115,116,100,105,111, | ||||
|     90,14,98,117,102,102,101,114,101,100,95,115,116,100,105,111, | ||||
|     122,7,99,111,110,102,105,103,32,122,2,58,32,41,7,218, | ||||
|     3,115,121,115,90,17,95,116,101,115,116,105,110,116,101,114, | ||||
|     110,97,108,99,97,112,105,218,5,112,114,105,110,116,218,4, | ||||
|     97,114,103,118,90,11,103,101,116,95,99,111,110,102,105,103, | ||||
|     115,114,2,0,0,0,218,3,107,101,121,169,0,243,0,0, | ||||
|     0,0,250,18,116,101,115,116,95,102,114,111,122,101,110,109, | ||||
|     97,105,110,46,112,121,218,8,60,109,111,100,117,108,101,62, | ||||
|     114,11,0,0,0,1,0,0,0,115,18,0,0,0,2,128, | ||||
|     8,3,8,1,8,2,12,1,12,1,8,1,26,7,4,249, | ||||
|     115,20,0,0,0,2,128,8,3,8,1,8,2,12,1,12, | ||||
|     1,2,7,4,1,2,249,30,7,115,88,0,0,0,0,0, | ||||
|     1,11,1,11,1,11,1,11,1,25,1,25,1,25,1,25, | ||||
|     1,6,7,27,1,28,1,28,1,6,7,17,19,22,19,27, | ||||
|     1,28,1,28,10,27,10,39,10,41,42,50,10,51,1,7, | ||||
|     12,2,1,42,1,42,5,8,5,10,11,41,21,24,11,41, | ||||
|     11,41,28,34,35,38,28,39,11,41,11,41,5,42,5,42, | ||||
|     5,42,1,42,1,42,114,9,0,0,0, | ||||
| }; | ||||
|  |  | |||
|  | @ -1546,6 +1546,17 @@ eval_frame_handle_pending(PyThreadState *tstate) | |||
| 
 | ||||
| #define TRACE_FUNCTION_ENTRY() \ | ||||
|     if (cframe.use_tracing) { \ | ||||
|         _PyFrame_SetStackPointer(frame, stack_pointer); \ | ||||
|         int err = trace_function_entry(tstate, frame); \ | ||||
|         stack_pointer = _PyFrame_GetStackPointer(frame); \ | ||||
|         if (err) { \ | ||||
|             goto error; \ | ||||
|         } \ | ||||
|     } | ||||
| 
 | ||||
| #define TRACE_FUNCTION_THROW_ENTRY() \ | ||||
|     if (cframe.use_tracing) { \ | ||||
|         assert(frame->stacktop >= 0); \ | ||||
|         if (trace_function_entry(tstate, frame)) { \ | ||||
|             goto exit_unwind; \ | ||||
|         } \ | ||||
|  | @ -1694,7 +1705,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             tstate->recursion_remaining--; | ||||
|             goto exit_unwind; | ||||
|         } | ||||
|         TRACE_FUNCTION_ENTRY(); | ||||
|         TRACE_FUNCTION_THROW_ENTRY(); | ||||
|         DTRACE_FUNCTION_ENTRY(); | ||||
|         goto resume_with_error; | ||||
|     } | ||||
|  | @ -1734,17 +1745,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|         goto exit_unwind; | ||||
|     } | ||||
| 
 | ||||
|     assert(tstate->cframe == &cframe); | ||||
|     assert(frame == cframe.current_frame); | ||||
| 
 | ||||
|     TRACE_FUNCTION_ENTRY(); | ||||
|     DTRACE_FUNCTION_ENTRY(); | ||||
| 
 | ||||
|     if (_Py_IncrementCountAndMaybeQuicken(frame->f_code) < 0) { | ||||
|         goto exit_unwind; | ||||
|     } | ||||
|     frame->f_state = FRAME_EXECUTING; | ||||
| 
 | ||||
| resume_frame: | ||||
|     SET_LOCALS_FROM_FRAME(); | ||||
| 
 | ||||
|  | @ -1825,6 +1825,24 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             DISPATCH(); | ||||
|         } | ||||
| 
 | ||||
|         TARGET(RESUME) { | ||||
|             assert(tstate->cframe == &cframe); | ||||
|             assert(frame == cframe.current_frame); | ||||
| 
 | ||||
|             int err = _Py_IncrementCountAndMaybeQuicken(frame->f_code); | ||||
|             if (err) { | ||||
|                 if (err < 0) { | ||||
|                     goto error; | ||||
|                 } | ||||
|                 /* Update first_instr and next_instr to point to newly quickened code */ | ||||
|                 int nexti = INSTR_OFFSET(); | ||||
|                 first_instr = frame->f_code->co_firstinstr; | ||||
|                 next_instr = first_instr + nexti; | ||||
|             } | ||||
|             frame->f_state = FRAME_EXECUTING; | ||||
|             DISPATCH(); | ||||
|         } | ||||
| 
 | ||||
|         TARGET(LOAD_CLOSURE) { | ||||
|             /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */ | ||||
|             PyObject *value = GETLOCAL(oparg); | ||||
|  | @ -3134,7 +3152,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             PyObject *initial = GETLOCAL(oparg); | ||||
|             PyObject *cell = PyCell_New(initial); | ||||
|             if (cell == NULL) { | ||||
|                 goto error; | ||||
|                 goto resume_with_error; | ||||
|             } | ||||
|             SETLOCAL(oparg, cell); | ||||
|             DISPATCH(); | ||||
|  | @ -5209,10 +5227,16 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
|             int instr_prev = skip_backwards_over_extended_args(frame->f_code, frame->f_lasti); | ||||
|             frame->f_lasti = INSTR_OFFSET(); | ||||
|             TRACING_NEXTOPARG(); | ||||
|             if (opcode == RESUME) { | ||||
|                 /* Call tracing */ | ||||
|                 TRACE_FUNCTION_ENTRY(); | ||||
|                 DTRACE_FUNCTION_ENTRY(); | ||||
|             } | ||||
|             else { | ||||
|                 /* line-by-line tracing support */ | ||||
|                 if (PyDTrace_LINE_ENABLED()) { | ||||
|                     maybe_dtrace_line(frame, &tstate->trace_info, instr_prev); | ||||
|                 } | ||||
|             /* line-by-line tracing support */ | ||||
| 
 | ||||
|                 if (cframe.use_tracing && | ||||
|                     tstate->c_tracefunc != NULL && !tstate->tracing) { | ||||
|  | @ -5234,8 +5258,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr | |||
| 
 | ||||
|                     stack_pointer = _PyFrame_GetStackPointer(frame); | ||||
|                     frame->stacktop = -1; | ||||
|                 TRACING_NEXTOPARG(); | ||||
|                 } | ||||
|             } | ||||
|             TRACING_NEXTOPARG(); | ||||
|             PRE_DISPATCH_GOTO(); | ||||
|             DISPATCH_GOTO(); | ||||
|         } | ||||
|  | @ -6046,6 +6071,7 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func, | |||
|         return NULL; | ||||
|     } | ||||
|     PyObject *retval = _PyEval_EvalFrame(tstate, frame, 0); | ||||
|     assert(frame->stacktop >= 0); | ||||
|     assert(_PyFrame_GetStackPointer(frame) == _PyFrame_Stackbase(frame)); | ||||
|     _PyEvalFrameClearAndPop(tstate, frame); | ||||
|     return retval; | ||||
|  | @ -6492,13 +6518,9 @@ call_trace(Py_tracefunc func, PyObject *obj, | |||
|     if (f == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     if (frame->f_lasti < 0) { | ||||
|         f->f_lineno = frame->f_code->co_firstlineno; | ||||
|     } | ||||
|     else { | ||||
|     assert (frame->f_lasti >= 0); | ||||
|     initialize_trace_info(&tstate->trace_info, frame); | ||||
|     f->f_lineno = _PyCode_CheckLineNumber(frame->f_lasti*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); | ||||
|     } | ||||
|     result = func(obj, f, what, arg); | ||||
|     f->f_lineno = 0; | ||||
|     _PyThreadState_ResumeTracing(tstate); | ||||
|  | @ -6534,7 +6556,14 @@ maybe_call_line_trace(Py_tracefunc func, PyObject *obj, | |||
|        then call the trace function if we're tracing source lines. | ||||
|     */ | ||||
|     initialize_trace_info(&tstate->trace_info, frame); | ||||
|     int lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); | ||||
|     _Py_CODEUNIT prev = ((_Py_CODEUNIT *)PyBytes_AS_STRING(frame->f_code->co_code))[instr_prev]; | ||||
|     int lastline; | ||||
|     if (_Py_OPCODE(prev) == RESUME && _Py_OPARG(prev) == 0) { | ||||
|         lastline = -1; | ||||
|     } | ||||
|     else { | ||||
|         lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); | ||||
|     } | ||||
|     int line = _PyCode_CheckLineNumber(frame->f_lasti*sizeof(_Py_CODEUNIT), &tstate->trace_info.bounds); | ||||
|     PyFrameObject *f = _PyFrame_GetFrameObject(frame); | ||||
|     if (f == NULL) { | ||||
|  |  | |||
|  | @ -689,9 +689,9 @@ compiler_enter_scope(struct compiler *c, identifier name, | |||
|     u->u_blocks = NULL; | ||||
|     u->u_nfblocks = 0; | ||||
|     u->u_firstlineno = lineno; | ||||
|     u->u_lineno = 0; | ||||
|     u->u_lineno = lineno; | ||||
|     u->u_col_offset = 0; | ||||
|     u->u_end_lineno = 0; | ||||
|     u->u_end_lineno = lineno; | ||||
|     u->u_end_col_offset = 0; | ||||
|     u->u_consts = PyDict_New(); | ||||
|     if (!u->u_consts) { | ||||
|  | @ -995,6 +995,7 @@ stack_effect(int opcode, int oparg, int jump) | |||
|     switch (opcode) { | ||||
|         case NOP: | ||||
|         case EXTENDED_ARG: | ||||
|         case RESUME: | ||||
|             return 0; | ||||
| 
 | ||||
|         /* Stack manipulation */ | ||||
|  | @ -1664,8 +1665,8 @@ compiler_addop_j_noline(struct compiler *c, int opcode, basicblock *b) | |||
|    the ASDL name to synthesize the name of the C type and the visit function. | ||||
| */ | ||||
| 
 | ||||
| #define ADD_YIELD_FROM(C) \ | ||||
|     RETURN_IF_FALSE(compiler_add_yield_from((C))) | ||||
| #define ADD_YIELD_FROM(C, await) \ | ||||
|     RETURN_IF_FALSE(compiler_add_yield_from((C), (await))) | ||||
| 
 | ||||
| #define POP_EXCEPT_AND_RERAISE(C) \ | ||||
|     RETURN_IF_FALSE(compiler_pop_except_and_reraise((C))) | ||||
|  | @ -1823,18 +1824,19 @@ compiler_call_exit_with_nones(struct compiler *c) { | |||
| } | ||||
| 
 | ||||
| static int | ||||
| compiler_add_yield_from(struct compiler *c) | ||||
| compiler_add_yield_from(struct compiler *c, int await) | ||||
| { | ||||
|     basicblock *start, *jump, *exit; | ||||
|     basicblock *start, *resume, *exit; | ||||
|     start = compiler_new_block(c); | ||||
|     jump = compiler_new_block(c); | ||||
|     resume = compiler_new_block(c); | ||||
|     exit = compiler_new_block(c); | ||||
|     if (start == NULL || jump == NULL || exit == NULL) { | ||||
|     if (start == NULL || resume == NULL || exit == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|     compiler_use_next_block(c, start); | ||||
|     ADDOP_JUMP(c, SEND, exit); | ||||
|     compiler_use_next_block(c, jump); | ||||
|     compiler_use_next_block(c, resume); | ||||
|     ADDOP_I(c, RESUME, await ? 3 : 2); | ||||
|     ADDOP_JUMP(c, JUMP_ABSOLUTE, start); | ||||
|     compiler_use_next_block(c, exit); | ||||
|     return 1; | ||||
|  | @ -1928,7 +1930,7 @@ compiler_unwind_fblock(struct compiler *c, struct fblockinfo *info, | |||
|             if (info->fb_type == ASYNC_WITH) { | ||||
|                 ADDOP(c, GET_AWAITABLE); | ||||
|                 ADDOP_LOAD_CONST(c, Py_None); | ||||
|                 ADD_YIELD_FROM(c); | ||||
|                 ADD_YIELD_FROM(c, 1); | ||||
|             } | ||||
|             ADDOP(c, POP_TOP); | ||||
|             /* The exit block should appear to execute after the
 | ||||
|  | @ -2047,9 +2049,11 @@ compiler_mod(struct compiler *c, mod_ty mod) | |||
|     if (module == NULL) { | ||||
|         return 0; | ||||
|     } | ||||
|     /* Use 0 for firstlineno initially, will fixup in assemble(). */ | ||||
|     if (!compiler_enter_scope(c, module, COMPILER_SCOPE_MODULE, mod, 1)) | ||||
|         return NULL; | ||||
|     c->u->u_lineno = -1; | ||||
|     ADDOP_I(c, RESUME, 0); | ||||
|     c->u->u_lineno = 1; | ||||
|     switch (mod->kind) { | ||||
|     case Module_kind: | ||||
|         if (!compiler_body(c, mod->v.Module.body)) { | ||||
|  | @ -2504,6 +2508,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async) | |||
|     if (!compiler_enter_scope(c, name, scope_type, (void *)s, firstlineno)) { | ||||
|         return 0; | ||||
|     } | ||||
|     ADDOP_I(c, RESUME, 0); | ||||
| 
 | ||||
|     /* if not -OO mode, add docstring */ | ||||
|     if (c->c_optimize < 2) { | ||||
|  | @ -2573,8 +2578,10 @@ compiler_class(struct compiler *c, stmt_ty s) | |||
| 
 | ||||
|     /* 1. compile the class body into a code object */ | ||||
|     if (!compiler_enter_scope(c, s->v.ClassDef.name, | ||||
|                               COMPILER_SCOPE_CLASS, (void *)s, firstlineno)) | ||||
|                               COMPILER_SCOPE_CLASS, (void *)s, firstlineno)) { | ||||
|         return 0; | ||||
|     } | ||||
|     ADDOP_I(c, RESUME, 0); | ||||
|     /* this block represents what we do in the new scope */ | ||||
|     { | ||||
|         /* use the class name for name mangling */ | ||||
|  | @ -2907,11 +2914,13 @@ compiler_lambda(struct compiler *c, expr_ty e) | |||
|     if (funcflags == -1) { | ||||
|         return 0; | ||||
|     } | ||||
|     ADDOP_I(c, RESUME, 0); | ||||
| 
 | ||||
|     if (!compiler_enter_scope(c, name, COMPILER_SCOPE_LAMBDA, | ||||
|                               (void *)e, e->lineno)) | ||||
|         return 0; | ||||
| 
 | ||||
|     ADDOP_I(c, RESUME, 0); | ||||
|     /* Make None the first constant, so the lambda can't have a
 | ||||
|        docstring. */ | ||||
|     if (compiler_add_const(c, Py_None) < 0) | ||||
|  | @ -3041,7 +3050,7 @@ compiler_async_for(struct compiler *c, stmt_ty s) | |||
|     ADDOP_JUMP(c, SETUP_FINALLY, except); | ||||
|     ADDOP(c, GET_ANEXT); | ||||
|     ADDOP_LOAD_CONST(c, Py_None); | ||||
|     ADD_YIELD_FROM(c); | ||||
|     ADD_YIELD_FROM(c, 1); | ||||
|     ADDOP(c, POP_BLOCK);  /* for SETUP_FINALLY */ | ||||
| 
 | ||||
|     /* Success block for __anext__ */ | ||||
|  | @ -5135,6 +5144,7 @@ compiler_sync_comprehension_generator(struct compiler *c, | |||
|         case COMP_GENEXP: | ||||
|             VISIT(c, expr, elt); | ||||
|             ADDOP(c, YIELD_VALUE); | ||||
|             ADDOP_I(c, RESUME, 1); | ||||
|             ADDOP(c, POP_TOP); | ||||
|             break; | ||||
|         case COMP_LISTCOMP: | ||||
|  | @ -5207,7 +5217,7 @@ compiler_async_comprehension_generator(struct compiler *c, | |||
|     ADDOP_JUMP(c, SETUP_FINALLY, except); | ||||
|     ADDOP(c, GET_ANEXT); | ||||
|     ADDOP_LOAD_CONST(c, Py_None); | ||||
|     ADD_YIELD_FROM(c); | ||||
|     ADD_YIELD_FROM(c, 1); | ||||
|     ADDOP(c, POP_BLOCK); | ||||
|     VISIT(c, expr, gen->target); | ||||
| 
 | ||||
|  | @ -5233,6 +5243,7 @@ compiler_async_comprehension_generator(struct compiler *c, | |||
|         case COMP_GENEXP: | ||||
|             VISIT(c, expr, elt); | ||||
|             ADDOP(c, YIELD_VALUE); | ||||
|             ADDOP_I(c, RESUME, 1); | ||||
|             ADDOP(c, POP_TOP); | ||||
|             break; | ||||
|         case COMP_LISTCOMP: | ||||
|  | @ -5285,6 +5296,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, | |||
|     { | ||||
|         goto error; | ||||
|     } | ||||
|     ADDOP_I(c, RESUME, 0); | ||||
|     SET_LOC(c, e); | ||||
| 
 | ||||
|     is_async_generator = c->u->u_ste->ste_coroutine; | ||||
|  | @ -5357,7 +5369,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type, | |||
|     if (is_async_generator && type != COMP_GENEXP) { | ||||
|         ADDOP(c, GET_AWAITABLE); | ||||
|         ADDOP_LOAD_CONST(c, Py_None); | ||||
|         ADD_YIELD_FROM(c); | ||||
|         ADD_YIELD_FROM(c, 1); | ||||
|     } | ||||
| 
 | ||||
|     return 1; | ||||
|  | @ -5506,7 +5518,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) | |||
|     ADDOP(c, BEFORE_ASYNC_WITH); | ||||
|     ADDOP(c, GET_AWAITABLE); | ||||
|     ADDOP_LOAD_CONST(c, Py_None); | ||||
|     ADD_YIELD_FROM(c); | ||||
|     ADD_YIELD_FROM(c, 1); | ||||
| 
 | ||||
|     ADDOP_JUMP(c, SETUP_WITH, final); | ||||
| 
 | ||||
|  | @ -5543,7 +5555,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) | |||
|         return 0; | ||||
|     ADDOP(c, GET_AWAITABLE); | ||||
|     ADDOP_LOAD_CONST(c, Py_None); | ||||
|     ADD_YIELD_FROM(c); | ||||
|     ADD_YIELD_FROM(c, 1); | ||||
| 
 | ||||
|     ADDOP(c, POP_TOP); | ||||
| 
 | ||||
|  | @ -5557,7 +5569,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos) | |||
|     ADDOP(c, WITH_EXCEPT_START); | ||||
|     ADDOP(c, GET_AWAITABLE); | ||||
|     ADDOP_LOAD_CONST(c, Py_None); | ||||
|     ADD_YIELD_FROM(c); | ||||
|     ADD_YIELD_FROM(c, 1); | ||||
|     compiler_with_except_finish(c, cleanup); | ||||
| 
 | ||||
|     compiler_use_next_block(c, exit); | ||||
|  | @ -5703,6 +5715,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) | |||
|             ADDOP_LOAD_CONST(c, Py_None); | ||||
|         } | ||||
|         ADDOP(c, YIELD_VALUE); | ||||
|         ADDOP_I(c, RESUME, 1); | ||||
|         break; | ||||
|     case YieldFrom_kind: | ||||
|         if (c->u->u_ste->ste_type != FunctionBlock) | ||||
|  | @ -5714,7 +5727,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) | |||
|         VISIT(c, expr, e->v.YieldFrom.value); | ||||
|         ADDOP(c, GET_YIELD_FROM_ITER); | ||||
|         ADDOP_LOAD_CONST(c, Py_None); | ||||
|         ADD_YIELD_FROM(c); | ||||
|         ADD_YIELD_FROM(c, 0); | ||||
|         break; | ||||
|     case Await_kind: | ||||
|         if (!IS_TOP_LEVEL_AWAIT(c)){ | ||||
|  | @ -5731,7 +5744,7 @@ compiler_visit_expr1(struct compiler *c, expr_ty e) | |||
|         VISIT(c, expr, e->v.Await.value); | ||||
|         ADDOP(c, GET_AWAITABLE); | ||||
|         ADDOP_LOAD_CONST(c, Py_None); | ||||
|         ADD_YIELD_FROM(c); | ||||
|         ADD_YIELD_FROM(c, 1); | ||||
|         break; | ||||
|     case Compare_kind: | ||||
|         return compiler_compare(c, e); | ||||
|  | @ -7987,6 +8000,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock, | |||
|     if (flags < 0) { | ||||
|         return -1; | ||||
|     } | ||||
|     assert(c->u->u_firstlineno > 0); | ||||
| 
 | ||||
|     /* Set up cells for any variable that escapes, to be put in a closure. */ | ||||
|     const int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars); | ||||
|  | @ -8191,19 +8205,21 @@ assemble(struct compiler *c, int addNone) | |||
|         goto error; | ||||
|     } | ||||
| 
 | ||||
|     /* Set firstlineno if it wasn't explicitly set. */ | ||||
|     if (!c->u->u_firstlineno) { | ||||
|         if (entryblock->b_instr && entryblock->b_instr->i_lineno) { | ||||
|             c->u->u_firstlineno = entryblock->b_instr->i_lineno; | ||||
|         } | ||||
|         else { | ||||
|             c->u->u_firstlineno = 1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // This must be called before fix_cell_offsets().
 | ||||
|     if (insert_prefix_instructions(c, entryblock, cellfixedoffsets, nfreevars)) { | ||||
|         goto error; | ||||
|     } | ||||
| 
 | ||||
|     /* Set firstlineno if it wasn't explicitly set. */ | ||||
|     if (!c->u->u_firstlineno) { | ||||
|         if (entryblock->b_instr && entryblock->b_instr->i_lineno) | ||||
|             c->u->u_firstlineno = entryblock->b_instr->i_lineno; | ||||
|        else | ||||
|             c->u->u_firstlineno = 1; | ||||
|     } | ||||
| 
 | ||||
|     if (!assemble_init(&a, nblocks, c->u->u_firstlineno)) | ||||
|         goto error; | ||||
|     a.a_entry = entryblock; | ||||
|  |  | |||
							
								
								
									
										2
									
								
								Python/opcode_targets.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Python/opcode_targets.h
									
										
									
										generated
									
									
									
								
							|  | @ -150,7 +150,7 @@ static void *opcode_targets[256] = { | |||
|     &&TARGET_LOAD_CLASSDEREF, | ||||
|     &&TARGET_COPY_FREE_VARS, | ||||
|     &&_unknown_opcode, | ||||
|     &&_unknown_opcode, | ||||
|     &&TARGET_RESUME, | ||||
|     &&TARGET_MATCH_CLASS, | ||||
|     &&_unknown_opcode, | ||||
|     &&_unknown_opcode, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Mark Shannon
						Mark Shannon