mirror of
				https://github.com/python/cpython.git
				synced 2025-10-24 18:33:49 +00:00 
			
		
		
		
	GH-118095: Handle RETURN_GENERATOR in tier 2 (GH-118180)
				
					
				
			This commit is contained in:
		
							parent
							
								
									10bb90ed49
								
							
						
					
					
						commit
						f180b31e76
					
				
					 16 changed files with 143 additions and 81 deletions
				
			
		|  | @ -182,7 +182,7 @@ static inline void _Py_LeaveRecursiveCall(void)  { | ||||||
| 
 | 
 | ||||||
| extern struct _PyInterpreterFrame* _PyEval_GetFrame(void); | extern struct _PyInterpreterFrame* _PyEval_GetFrame(void); | ||||||
| 
 | 
 | ||||||
| extern PyObject* _Py_MakeCoro(PyFunctionObject *func); | PyAPI_FUNC(PyObject *)_Py_MakeCoro(PyFunctionObject *func); | ||||||
| 
 | 
 | ||||||
| /* Handle signals, pending calls, GIL drop request
 | /* Handle signals, pending calls, GIL drop request
 | ||||||
|    and asynchronous exception */ |    and asynchronous exception */ | ||||||
|  |  | ||||||
|  | @ -110,7 +110,17 @@ _PyFrame_NumSlotsForCodeObject(PyCodeObject *code) | ||||||
|     return code->co_framesize - FRAME_SPECIALS_SIZE; |     return code->co_framesize - FRAME_SPECIALS_SIZE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest); | static inline void _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) | ||||||
|  | { | ||||||
|  |     assert(src->stacktop >= _PyFrame_GetCode(src)->co_nlocalsplus); | ||||||
|  |     *dest = *src; | ||||||
|  |     for (int i = 1; i < src->stacktop; i++) { | ||||||
|  |         dest->localsplus[i] = src->localsplus[i]; | ||||||
|  |     } | ||||||
|  |     // Don't leave a dangling pointer to the old frame when creating generators
 | ||||||
|  |     // and coroutines:
 | ||||||
|  |     dest->previous = NULL; | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| /* Consumes reference to func and locals.
 | /* Consumes reference to func and locals.
 | ||||||
|    Does not initialize frame->previous, which happens |    Does not initialize frame->previous, which happens | ||||||
|  | @ -256,7 +266,7 @@ _PyThreadState_HasStackSpace(PyThreadState *tstate, int size) | ||||||
| extern _PyInterpreterFrame * | extern _PyInterpreterFrame * | ||||||
| _PyThreadState_PushFrame(PyThreadState *tstate, size_t size); | _PyThreadState_PushFrame(PyThreadState *tstate, size_t size); | ||||||
| 
 | 
 | ||||||
| void _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame); | PyAPI_FUNC(void) _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame *frame); | ||||||
| 
 | 
 | ||||||
| /* Pushes a frame without checking for space.
 | /* Pushes a frame without checking for space.
 | ||||||
|  * Must be guarded by _PyThreadState_HasStackSpace() |  * Must be guarded by _PyThreadState_HasStackSpace() | ||||||
|  |  | ||||||
							
								
								
									
										3
									
								
								Include/internal/pycore_opcode_metadata.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										3
									
								
								Include/internal/pycore_opcode_metadata.h
									
										
									
										generated
									
									
									
								
							|  | @ -805,7 +805,7 @@ int _PyOpcode_num_pushed(int opcode, int oparg)  { | ||||||
|         case RETURN_CONST: |         case RETURN_CONST: | ||||||
|             return 0; |             return 0; | ||||||
|         case RETURN_GENERATOR: |         case RETURN_GENERATOR: | ||||||
|             return 0; |             return 1; | ||||||
|         case RETURN_VALUE: |         case RETURN_VALUE: | ||||||
|             return 0; |             return 0; | ||||||
|         case SEND: |         case SEND: | ||||||
|  | @ -1310,6 +1310,7 @@ _PyOpcode_macro_expansion[256] = { | ||||||
|     [PUSH_NULL] = { .nuops = 1, .uops = { { _PUSH_NULL, 0, 0 } } }, |     [PUSH_NULL] = { .nuops = 1, .uops = { { _PUSH_NULL, 0, 0 } } }, | ||||||
|     [RESUME_CHECK] = { .nuops = 1, .uops = { { _RESUME_CHECK, 0, 0 } } }, |     [RESUME_CHECK] = { .nuops = 1, .uops = { { _RESUME_CHECK, 0, 0 } } }, | ||||||
|     [RETURN_CONST] = { .nuops = 2, .uops = { { _LOAD_CONST, 0, 0 }, { _POP_FRAME, 0, 0 } } }, |     [RETURN_CONST] = { .nuops = 2, .uops = { { _LOAD_CONST, 0, 0 }, { _POP_FRAME, 0, 0 } } }, | ||||||
|  |     [RETURN_GENERATOR] = { .nuops = 1, .uops = { { _RETURN_GENERATOR, 0, 0 } } }, | ||||||
|     [RETURN_VALUE] = { .nuops = 1, .uops = { { _POP_FRAME, 0, 0 } } }, |     [RETURN_VALUE] = { .nuops = 1, .uops = { { _POP_FRAME, 0, 0 } } }, | ||||||
|     [SETUP_ANNOTATIONS] = { .nuops = 1, .uops = { { _SETUP_ANNOTATIONS, 0, 0 } } }, |     [SETUP_ANNOTATIONS] = { .nuops = 1, .uops = { { _SETUP_ANNOTATIONS, 0, 0 } } }, | ||||||
|     [SET_ADD] = { .nuops = 1, .uops = { { _SET_ADD, 0, 0 } } }, |     [SET_ADD] = { .nuops = 1, .uops = { { _SET_ADD, 0, 0 } } }, | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								Include/internal/pycore_uop_ids.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								Include/internal/pycore_uop_ids.h
									
										
									
										generated
									
									
									
								
							|  | @ -231,6 +231,7 @@ extern "C" { | ||||||
| #define _PUSH_NULL PUSH_NULL | #define _PUSH_NULL PUSH_NULL | ||||||
| #define _REPLACE_WITH_TRUE 424 | #define _REPLACE_WITH_TRUE 424 | ||||||
| #define _RESUME_CHECK RESUME_CHECK | #define _RESUME_CHECK RESUME_CHECK | ||||||
|  | #define _RETURN_GENERATOR RETURN_GENERATOR | ||||||
| #define _SAVE_RETURN_OFFSET 425 | #define _SAVE_RETURN_OFFSET 425 | ||||||
| #define _SEND 426 | #define _SEND 426 | ||||||
| #define _SEND_GEN SEND_GEN | #define _SEND_GEN SEND_GEN | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								Include/internal/pycore_uop_metadata.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Include/internal/pycore_uop_metadata.h
									
										
									
										generated
									
									
									
								
							|  | @ -219,6 +219,7 @@ const uint16_t _PyUop_Flags[MAX_UOP_ID+1] = { | ||||||
|     [_CALL_METHOD_DESCRIPTOR_FAST] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, |     [_CALL_METHOD_DESCRIPTOR_FAST] = HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, | ||||||
|     [_MAKE_FUNCTION] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, |     [_MAKE_FUNCTION] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, | ||||||
|     [_SET_FUNCTION_ATTRIBUTE] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, |     [_SET_FUNCTION_ATTRIBUTE] = HAS_ARG_FLAG | HAS_ESCAPES_FLAG, | ||||||
|  |     [_RETURN_GENERATOR] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG, | ||||||
|     [_BUILD_SLICE] = HAS_ARG_FLAG | HAS_ERROR_FLAG, |     [_BUILD_SLICE] = HAS_ARG_FLAG | HAS_ERROR_FLAG, | ||||||
|     [_CONVERT_VALUE] = HAS_ARG_FLAG | HAS_ERROR_FLAG, |     [_CONVERT_VALUE] = HAS_ARG_FLAG | HAS_ERROR_FLAG, | ||||||
|     [_FORMAT_SIMPLE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, |     [_FORMAT_SIMPLE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG, | ||||||
|  | @ -445,6 +446,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_ID+1] = { | ||||||
|     [_PUSH_NULL] = "_PUSH_NULL", |     [_PUSH_NULL] = "_PUSH_NULL", | ||||||
|     [_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE", |     [_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE", | ||||||
|     [_RESUME_CHECK] = "_RESUME_CHECK", |     [_RESUME_CHECK] = "_RESUME_CHECK", | ||||||
|  |     [_RETURN_GENERATOR] = "_RETURN_GENERATOR", | ||||||
|     [_SAVE_RETURN_OFFSET] = "_SAVE_RETURN_OFFSET", |     [_SAVE_RETURN_OFFSET] = "_SAVE_RETURN_OFFSET", | ||||||
|     [_SETUP_ANNOTATIONS] = "_SETUP_ANNOTATIONS", |     [_SETUP_ANNOTATIONS] = "_SETUP_ANNOTATIONS", | ||||||
|     [_SET_ADD] = "_SET_ADD", |     [_SET_ADD] = "_SET_ADD", | ||||||
|  | @ -894,6 +896,8 @@ int _PyUop_num_popped(int opcode, int oparg) | ||||||
|             return 1; |             return 1; | ||||||
|         case _SET_FUNCTION_ATTRIBUTE: |         case _SET_FUNCTION_ATTRIBUTE: | ||||||
|             return 2; |             return 2; | ||||||
|  |         case _RETURN_GENERATOR: | ||||||
|  |             return 0; | ||||||
|         case _BUILD_SLICE: |         case _BUILD_SLICE: | ||||||
|             return 2 + ((oparg == 3) ? 1 : 0); |             return 2 + ((oparg == 3) ? 1 : 0); | ||||||
|         case _CONVERT_VALUE: |         case _CONVERT_VALUE: | ||||||
|  |  | ||||||
|  | @ -1286,5 +1286,17 @@ def testfunc(n): | ||||||
|         self.assertEqual(res, 32 * 32) |         self.assertEqual(res, 32 * 32) | ||||||
|         self.assertIsNone(ex) |         self.assertIsNone(ex) | ||||||
| 
 | 
 | ||||||
|  |     def test_return_generator(self): | ||||||
|  |         def gen(): | ||||||
|  |             yield None | ||||||
|  |         def testfunc(n): | ||||||
|  |             for i in range(n): | ||||||
|  |                 gen() | ||||||
|  |             return i | ||||||
|  |         res, ex = self._run_with_optimizer(testfunc, 20) | ||||||
|  |         self.assertEqual(res, 19) | ||||||
|  |         self.assertIsNotNone(ex) | ||||||
|  |         self.assertIn("_RETURN_GENERATOR", get_opnames(ex)) | ||||||
|  | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     unittest.main() |     unittest.main() | ||||||
|  |  | ||||||
|  | @ -304,11 +304,6 @@ mark_stacks(PyCodeObject *code_obj, int len) | ||||||
|         stacks[i] = UNINITIALIZED; |         stacks[i] = UNINITIALIZED; | ||||||
|     } |     } | ||||||
|     stacks[0] = EMPTY_STACK; |     stacks[0] = EMPTY_STACK; | ||||||
|     if (code_obj->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) |  | ||||||
|     { |  | ||||||
|         // Generators get sent None while starting:
 |  | ||||||
|         stacks[0] = push_value(stacks[0], Object); |  | ||||||
|     } |  | ||||||
|     int todo = 1; |     int todo = 1; | ||||||
|     while (todo) { |     while (todo) { | ||||||
|         todo = 0; |         todo = 0; | ||||||
|  |  | ||||||
|  | @ -837,12 +837,7 @@ dummy_func( | ||||||
|             _PyFrame_StackPush(frame, retval); |             _PyFrame_StackPush(frame, retval); | ||||||
|             LOAD_SP(); |             LOAD_SP(); | ||||||
|             LOAD_IP(frame->return_offset); |             LOAD_IP(frame->return_offset); | ||||||
| #if LLTRACE && TIER_ONE |             LLTRACE_RESUME_FRAME(); | ||||||
|             lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); |  | ||||||
|             if (lltrace < 0) { |  | ||||||
|                 goto exit_unwind; |  | ||||||
|             } |  | ||||||
| #endif |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         macro(RETURN_VALUE) = |         macro(RETURN_VALUE) = | ||||||
|  | @ -3186,12 +3181,7 @@ dummy_func( | ||||||
|             tstate->py_recursion_remaining--; |             tstate->py_recursion_remaining--; | ||||||
|             LOAD_SP(); |             LOAD_SP(); | ||||||
|             LOAD_IP(0); |             LOAD_IP(0); | ||||||
| #if LLTRACE && TIER_ONE |             LLTRACE_RESUME_FRAME(); | ||||||
|             lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); |  | ||||||
|             if (lltrace < 0) { |  | ||||||
|                 goto exit_unwind; |  | ||||||
|             } |  | ||||||
| #endif |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         macro(CALL_BOUND_METHOD_EXACT_ARGS) = |         macro(CALL_BOUND_METHOD_EXACT_ARGS) = | ||||||
|  | @ -3877,7 +3867,7 @@ dummy_func( | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         tier1 inst(RETURN_GENERATOR, (--)) { |         inst(RETURN_GENERATOR, (-- res)) { | ||||||
|             assert(PyFunction_Check(frame->f_funcobj)); |             assert(PyFunction_Check(frame->f_funcobj)); | ||||||
|             PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; |             PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; | ||||||
|             PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); |             PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); | ||||||
|  | @ -3887,19 +3877,19 @@ dummy_func( | ||||||
|             assert(EMPTY()); |             assert(EMPTY()); | ||||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); |             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||||
|             _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; |             _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; | ||||||
|             frame->instr_ptr = next_instr; |             frame->instr_ptr++; | ||||||
|             _PyFrame_Copy(frame, gen_frame); |             _PyFrame_Copy(frame, gen_frame); | ||||||
|             assert(frame->frame_obj == NULL); |             assert(frame->frame_obj == NULL); | ||||||
|             gen->gi_frame_state = FRAME_CREATED; |             gen->gi_frame_state = FRAME_CREATED; | ||||||
|             gen_frame->owner = FRAME_OWNED_BY_GENERATOR; |             gen_frame->owner = FRAME_OWNED_BY_GENERATOR; | ||||||
|             _Py_LeaveRecursiveCallPy(tstate); |             _Py_LeaveRecursiveCallPy(tstate); | ||||||
|             assert(frame != &entry_frame); |             res = (PyObject *)gen; | ||||||
|             _PyInterpreterFrame *prev = frame->previous; |             _PyInterpreterFrame *prev = frame->previous; | ||||||
|             _PyThreadState_PopFrame(tstate, frame); |             _PyThreadState_PopFrame(tstate, frame); | ||||||
|             frame = tstate->current_frame = prev; |             frame = tstate->current_frame = prev; | ||||||
|             _PyFrame_StackPush(frame, (PyObject *)gen); |  | ||||||
|             LOAD_IP(frame->return_offset); |             LOAD_IP(frame->return_offset); | ||||||
|             goto resume_frame; |             LOAD_SP(); | ||||||
|  |             LLTRACE_RESUME_FRAME(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         inst(BUILD_SLICE, (start, stop, step if (oparg == 3) -- slice)) { |         inst(BUILD_SLICE, (start, stop, step if (oparg == 3) -- slice)) { | ||||||
|  |  | ||||||
|  | @ -86,6 +86,18 @@ | ||||||
| #define PRE_DISPATCH_GOTO() ((void)0) | #define PRE_DISPATCH_GOTO() ((void)0) | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #if LLTRACE | ||||||
|  | #define LLTRACE_RESUME_FRAME() \ | ||||||
|  | do { \ | ||||||
|  |     lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); \ | ||||||
|  |     if (lltrace < 0) { \ | ||||||
|  |         goto exit_unwind; \ | ||||||
|  |     } \ | ||||||
|  | } while (0) | ||||||
|  | #else | ||||||
|  | #define LLTRACE_RESUME_FRAME() ((void)0) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef Py_GIL_DISABLED | #ifdef Py_GIL_DISABLED | ||||||
| #define QSBR_QUIESCENT_STATE(tstate) _Py_qsbr_quiescent_state(((_PyThreadStateImpl *)tstate)->qsbr) | #define QSBR_QUIESCENT_STATE(tstate) _Py_qsbr_quiescent_state(((_PyThreadStateImpl *)tstate)->qsbr) | ||||||
| #else | #else | ||||||
|  |  | ||||||
							
								
								
									
										43
									
								
								Python/executor_cases.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										43
									
								
								Python/executor_cases.c.h
									
										
									
										generated
									
									
									
								
							|  | @ -988,12 +988,7 @@ | ||||||
|             _PyFrame_StackPush(frame, retval); |             _PyFrame_StackPush(frame, retval); | ||||||
|             LOAD_SP(); |             LOAD_SP(); | ||||||
|             LOAD_IP(frame->return_offset); |             LOAD_IP(frame->return_offset); | ||||||
|             #if LLTRACE && TIER_ONE |             LLTRACE_RESUME_FRAME(); | ||||||
|             lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); |  | ||||||
|             if (lltrace < 0) { |  | ||||||
|                 goto exit_unwind; |  | ||||||
|             } |  | ||||||
|             #endif |  | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -3213,12 +3208,7 @@ | ||||||
|             tstate->py_recursion_remaining--; |             tstate->py_recursion_remaining--; | ||||||
|             LOAD_SP(); |             LOAD_SP(); | ||||||
|             LOAD_IP(0); |             LOAD_IP(0); | ||||||
|             #if LLTRACE && TIER_ONE |             LLTRACE_RESUME_FRAME(); | ||||||
|             lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); |  | ||||||
|             if (lltrace < 0) { |  | ||||||
|                 goto exit_unwind; |  | ||||||
|             } |  | ||||||
|             #endif |  | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -3833,6 +3823,35 @@ | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         case _RETURN_GENERATOR: { | ||||||
|  |             PyObject *res; | ||||||
|  |             assert(PyFunction_Check(frame->f_funcobj)); | ||||||
|  |             PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; | ||||||
|  |             PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); | ||||||
|  |             if (gen == NULL) { | ||||||
|  |                 JUMP_TO_ERROR(); | ||||||
|  |             } | ||||||
|  |             assert(EMPTY()); | ||||||
|  |             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||||
|  |             _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; | ||||||
|  |             frame->instr_ptr++; | ||||||
|  |             _PyFrame_Copy(frame, gen_frame); | ||||||
|  |             assert(frame->frame_obj == NULL); | ||||||
|  |             gen->gi_frame_state = FRAME_CREATED; | ||||||
|  |             gen_frame->owner = FRAME_OWNED_BY_GENERATOR; | ||||||
|  |             _Py_LeaveRecursiveCallPy(tstate); | ||||||
|  |             res = (PyObject *)gen; | ||||||
|  |             _PyInterpreterFrame *prev = frame->previous; | ||||||
|  |             _PyThreadState_PopFrame(tstate, frame); | ||||||
|  |             frame = tstate->current_frame = prev; | ||||||
|  |             LOAD_IP(frame->return_offset); | ||||||
|  |             LOAD_SP(); | ||||||
|  |             LLTRACE_RESUME_FRAME(); | ||||||
|  |             stack_pointer[0] = res; | ||||||
|  |             stack_pointer += 1; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         case _BUILD_SLICE: { |         case _BUILD_SLICE: { | ||||||
|             PyObject *step = NULL; |             PyObject *step = NULL; | ||||||
|             PyObject *stop; |             PyObject *stop; | ||||||
|  |  | ||||||
|  | @ -53,18 +53,6 @@ _PyFrame_MakeAndSetFrameObject(_PyInterpreterFrame *frame) | ||||||
|     return f; |     return f; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void |  | ||||||
| _PyFrame_Copy(_PyInterpreterFrame *src, _PyInterpreterFrame *dest) |  | ||||||
| { |  | ||||||
|     assert(src->stacktop >= _PyFrame_GetCode(src)->co_nlocalsplus); |  | ||||||
|     Py_ssize_t size = ((char*)&src->localsplus[src->stacktop]) - (char *)src; |  | ||||||
|     memcpy(dest, src, size); |  | ||||||
|     // Don't leave a dangling pointer to the old frame when creating generators
 |  | ||||||
|     // and coroutines:
 |  | ||||||
|     dest->previous = NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| static void | static void | ||||||
| take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) | take_ownership(PyFrameObject *f, _PyInterpreterFrame *frame) | ||||||
| { | { | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								Python/generated_cases.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										40
									
								
								Python/generated_cases.c.h
									
										
									
										generated
									
									
									
								
							|  | @ -997,12 +997,7 @@ | ||||||
|                 tstate->py_recursion_remaining--; |                 tstate->py_recursion_remaining--; | ||||||
|                 LOAD_SP(); |                 LOAD_SP(); | ||||||
|                 LOAD_IP(0); |                 LOAD_IP(0); | ||||||
|                 #if LLTRACE && TIER_ONE |                 LLTRACE_RESUME_FRAME(); | ||||||
|                 lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); |  | ||||||
|                 if (lltrace < 0) { |  | ||||||
|                     goto exit_unwind; |  | ||||||
|                 } |  | ||||||
|                 #endif |  | ||||||
|             } |             } | ||||||
|             DISPATCH(); |             DISPATCH(); | ||||||
|         } |         } | ||||||
|  | @ -1786,12 +1781,7 @@ | ||||||
|                 tstate->py_recursion_remaining--; |                 tstate->py_recursion_remaining--; | ||||||
|                 LOAD_SP(); |                 LOAD_SP(); | ||||||
|                 LOAD_IP(0); |                 LOAD_IP(0); | ||||||
|                 #if LLTRACE && TIER_ONE |                 LLTRACE_RESUME_FRAME(); | ||||||
|                 lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); |  | ||||||
|                 if (lltrace < 0) { |  | ||||||
|                     goto exit_unwind; |  | ||||||
|                 } |  | ||||||
|                 #endif |  | ||||||
|             } |             } | ||||||
|             DISPATCH(); |             DISPATCH(); | ||||||
|         } |         } | ||||||
|  | @ -4992,12 +4982,7 @@ | ||||||
|                 _PyFrame_StackPush(frame, retval); |                 _PyFrame_StackPush(frame, retval); | ||||||
|                 LOAD_SP(); |                 LOAD_SP(); | ||||||
|                 LOAD_IP(frame->return_offset); |                 LOAD_IP(frame->return_offset); | ||||||
|                 #if LLTRACE && TIER_ONE |                 LLTRACE_RESUME_FRAME(); | ||||||
|                 lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); |  | ||||||
|                 if (lltrace < 0) { |  | ||||||
|                     goto exit_unwind; |  | ||||||
|                 } |  | ||||||
|                 #endif |  | ||||||
|             } |             } | ||||||
|             DISPATCH(); |             DISPATCH(); | ||||||
|         } |         } | ||||||
|  | @ -5006,6 +4991,7 @@ | ||||||
|             frame->instr_ptr = next_instr; |             frame->instr_ptr = next_instr; | ||||||
|             next_instr += 1; |             next_instr += 1; | ||||||
|             INSTRUCTION_STATS(RETURN_GENERATOR); |             INSTRUCTION_STATS(RETURN_GENERATOR); | ||||||
|  |             PyObject *res; | ||||||
|             assert(PyFunction_Check(frame->f_funcobj)); |             assert(PyFunction_Check(frame->f_funcobj)); | ||||||
|             PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; |             PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj; | ||||||
|             PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); |             PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func); | ||||||
|  | @ -5015,19 +5001,22 @@ | ||||||
|             assert(EMPTY()); |             assert(EMPTY()); | ||||||
|             _PyFrame_SetStackPointer(frame, stack_pointer); |             _PyFrame_SetStackPointer(frame, stack_pointer); | ||||||
|             _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; |             _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe; | ||||||
|             frame->instr_ptr = next_instr; |             frame->instr_ptr++; | ||||||
|             _PyFrame_Copy(frame, gen_frame); |             _PyFrame_Copy(frame, gen_frame); | ||||||
|             assert(frame->frame_obj == NULL); |             assert(frame->frame_obj == NULL); | ||||||
|             gen->gi_frame_state = FRAME_CREATED; |             gen->gi_frame_state = FRAME_CREATED; | ||||||
|             gen_frame->owner = FRAME_OWNED_BY_GENERATOR; |             gen_frame->owner = FRAME_OWNED_BY_GENERATOR; | ||||||
|             _Py_LeaveRecursiveCallPy(tstate); |             _Py_LeaveRecursiveCallPy(tstate); | ||||||
|             assert(frame != &entry_frame); |             res = (PyObject *)gen; | ||||||
|             _PyInterpreterFrame *prev = frame->previous; |             _PyInterpreterFrame *prev = frame->previous; | ||||||
|             _PyThreadState_PopFrame(tstate, frame); |             _PyThreadState_PopFrame(tstate, frame); | ||||||
|             frame = tstate->current_frame = prev; |             frame = tstate->current_frame = prev; | ||||||
|             _PyFrame_StackPush(frame, (PyObject *)gen); |  | ||||||
|             LOAD_IP(frame->return_offset); |             LOAD_IP(frame->return_offset); | ||||||
|             goto resume_frame; |             LOAD_SP(); | ||||||
|  |             LLTRACE_RESUME_FRAME(); | ||||||
|  |             stack_pointer[0] = res; | ||||||
|  |             stack_pointer += 1; | ||||||
|  |             DISPATCH(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         TARGET(RETURN_VALUE) { |         TARGET(RETURN_VALUE) { | ||||||
|  | @ -5050,12 +5039,7 @@ | ||||||
|             _PyFrame_StackPush(frame, retval); |             _PyFrame_StackPush(frame, retval); | ||||||
|             LOAD_SP(); |             LOAD_SP(); | ||||||
|             LOAD_IP(frame->return_offset); |             LOAD_IP(frame->return_offset); | ||||||
|             #if LLTRACE && TIER_ONE |             LLTRACE_RESUME_FRAME(); | ||||||
|             lltrace = maybe_lltrace_resume_frame(frame, &entry_frame, GLOBALS()); |  | ||||||
|             if (lltrace < 0) { |  | ||||||
|                 goto exit_unwind; |  | ||||||
|             } |  | ||||||
|             #endif |  | ||||||
|             DISPATCH(); |             DISPATCH(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -697,7 +697,8 @@ translate_bytecode_to_trace( | ||||||
|                     // Reserve space for nuops (+ _SET_IP + _EXIT_TRACE)
 |                     // Reserve space for nuops (+ _SET_IP + _EXIT_TRACE)
 | ||||||
|                     int nuops = expansion->nuops; |                     int nuops = expansion->nuops; | ||||||
|                     RESERVE(nuops + 1); /* One extra for exit */ |                     RESERVE(nuops + 1); /* One extra for exit */ | ||||||
|                     if (expansion->uops[nuops-1].uop == _POP_FRAME) { |                     int16_t last_op = expansion->uops[nuops-1].uop; | ||||||
|  |                     if (last_op == _POP_FRAME || last_op == _RETURN_GENERATOR) { | ||||||
|                         // Check for trace stack underflow now:
 |                         // Check for trace stack underflow now:
 | ||||||
|                         // We can't bail e.g. in the middle of
 |                         // We can't bail e.g. in the middle of
 | ||||||
|                         // LOAD_CONST + _POP_FRAME.
 |                         // LOAD_CONST + _POP_FRAME.
 | ||||||
|  | @ -756,7 +757,7 @@ translate_bytecode_to_trace( | ||||||
|                                 Py_FatalError("garbled expansion"); |                                 Py_FatalError("garbled expansion"); | ||||||
|                         } |                         } | ||||||
| 
 | 
 | ||||||
|                         if (uop == _POP_FRAME) { |                         if (uop == _POP_FRAME || uop == _RETURN_GENERATOR) { | ||||||
|                             TRACE_STACK_POP(); |                             TRACE_STACK_POP(); | ||||||
|                             /* Set the operand to the function or code object returned to,
 |                             /* Set the operand to the function or code object returned to,
 | ||||||
|                              * to assist optimization passes. (See _PUSH_FRAME below.) |                              * to assist optimization passes. (See _PUSH_FRAME below.) | ||||||
|  |  | ||||||
|  | @ -369,7 +369,7 @@ eliminate_pop_guard(_PyUOpInstruction *this_instr, bool exit) | ||||||
| static PyCodeObject * | static PyCodeObject * | ||||||
| get_code(_PyUOpInstruction *op) | get_code(_PyUOpInstruction *op) | ||||||
| { | { | ||||||
|     assert(op->opcode == _PUSH_FRAME || op->opcode == _POP_FRAME); |     assert(op->opcode == _PUSH_FRAME || op->opcode == _POP_FRAME || op->opcode == _RETURN_GENERATOR); | ||||||
|     PyCodeObject *co = NULL; |     PyCodeObject *co = NULL; | ||||||
|     uint64_t operand = op->operand; |     uint64_t operand = op->operand; | ||||||
|     if (operand == 0) { |     if (operand == 0) { | ||||||
|  |  | ||||||
|  | @ -651,6 +651,28 @@ dummy_func(void) { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     op(_RETURN_GENERATOR, ( -- res)) { | ||||||
|  |         SYNC_SP(); | ||||||
|  |         ctx->frame->stack_pointer = stack_pointer; | ||||||
|  |         frame_pop(ctx); | ||||||
|  |         stack_pointer = ctx->frame->stack_pointer; | ||||||
|  |         OUT_OF_SPACE_IF_NULL(res = sym_new_unknown(ctx)); | ||||||
|  | 
 | ||||||
|  |         /* Stack space handling */ | ||||||
|  |         assert(corresponding_check_stack == NULL); | ||||||
|  |         assert(co != NULL); | ||||||
|  |         int framesize = co->co_framesize; | ||||||
|  |         assert(framesize > 0); | ||||||
|  |         assert(framesize <= curr_space); | ||||||
|  |         curr_space -= framesize; | ||||||
|  | 
 | ||||||
|  |         co = get_code(this_instr); | ||||||
|  |         if (co == NULL) { | ||||||
|  |             // might be impossible, but bailing is still safe
 | ||||||
|  |             goto done; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     op(_CHECK_STACK_SPACE, ( --)) { |     op(_CHECK_STACK_SPACE, ( --)) { | ||||||
|         assert(corresponding_check_stack == NULL); |         assert(corresponding_check_stack == NULL); | ||||||
|         corresponding_check_stack = this_instr; |         corresponding_check_stack = this_instr; | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								Python/optimizer_cases.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										23
									
								
								Python/optimizer_cases.c.h
									
										
									
										generated
									
									
									
								
							|  | @ -1840,6 +1840,29 @@ | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         case _RETURN_GENERATOR: { | ||||||
|  |             _Py_UopsSymbol *res; | ||||||
|  |             ctx->frame->stack_pointer = stack_pointer; | ||||||
|  |             frame_pop(ctx); | ||||||
|  |             stack_pointer = ctx->frame->stack_pointer; | ||||||
|  |             OUT_OF_SPACE_IF_NULL(res = sym_new_unknown(ctx)); | ||||||
|  |             /* Stack space handling */ | ||||||
|  |             assert(corresponding_check_stack == NULL); | ||||||
|  |             assert(co != NULL); | ||||||
|  |             int framesize = co->co_framesize; | ||||||
|  |             assert(framesize > 0); | ||||||
|  |             assert(framesize <= curr_space); | ||||||
|  |             curr_space -= framesize; | ||||||
|  |             co = get_code(this_instr); | ||||||
|  |             if (co == NULL) { | ||||||
|  |                 // might be impossible, but bailing is still safe
 | ||||||
|  |                 goto done; | ||||||
|  |             } | ||||||
|  |             stack_pointer[0] = res; | ||||||
|  |             stack_pointer += 1; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         case _BUILD_SLICE: { |         case _BUILD_SLICE: { | ||||||
|             _Py_UopsSymbol *slice; |             _Py_UopsSymbol *slice; | ||||||
|             slice = sym_new_not_null(ctx); |             slice = sym_new_not_null(ctx); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Mark Shannon
						Mark Shannon