| #ifndef Py_BUILD_CORE |
| #define Py_BUILD_CORE |
| #endif |
| #ifndef Py_BUILD_CORE_MODULE |
| #define Py_BUILD_CORE_MODULE |
| #endif |
| |
| #include "../../Python/ceval.h" |
| |
| #include "../../Python/ceval_macros.h" |
| |
| int Test_EvalFrame_Resumes, Test_EvalFrame_Loads; |
| |
| #ifdef _Py_TIER2 |
| static int |
| stop_tracing_and_jit(PyThreadState *tstate, _PyInterpreterFrame *frame) |
| { |
| (void)(tstate); |
| (void)(frame); |
| return 0; |
| } |
| #endif |
| |
| _PyJitEntryFuncPtr _Py_jit_entry; |
| |
| #if _Py_TAIL_CALL_INTERP |
| #include "test_targets.h" |
| #include "test_cases.c.h" |
| #endif |
| |
| PyObject* _Py_HOT_FUNCTION |
| Test_EvalFrame(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag) |
| { |
| _Py_EnsureTstateNotNULL(tstate); |
| check_invalid_reentrancy(); |
| CALL_STAT_INC(pyeval_calls); |
| |
| #if USE_COMPUTED_GOTOS && !_Py_TAIL_CALL_INTERP |
| /* Import the static jump table */ |
| #include "test_targets.h" |
| void **opcode_targets = opcode_targets_table; |
| #endif |
| |
| #ifdef Py_STATS |
| int lastopcode = 0; |
| #endif |
| #if !_Py_TAIL_CALL_INTERP |
| uint8_t opcode; /* Current opcode */ |
| int oparg; /* Current opcode argument, if any */ |
| assert(tstate->current_frame == NULL || tstate->current_frame->stackpointer != NULL); |
| #if !USE_COMPUTED_GOTOS |
| uint8_t tracing_mode = 0; |
| uint8_t dispatch_code; |
| #endif |
| #endif |
| _PyEntryFrame entry; |
| |
| if (_Py_EnterRecursiveCallTstate(tstate, "")) { |
| assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); |
| _PyEval_FrameClearAndPop(tstate, frame); |
| return NULL; |
| } |
| |
| /* Local "register" variables. |
| * These are cached values from the frame and code object. */ |
| _Py_CODEUNIT *next_instr; |
| _PyStackRef *stack_pointer; |
| entry.stack[0] = PyStackRef_NULL; |
| #ifdef Py_STACKREF_DEBUG |
| entry.frame.f_funcobj = PyStackRef_None; |
| #elif defined(Py_DEBUG) |
| /* Set these to invalid but identifiable values for debugging. */ |
| entry.frame.f_funcobj = (_PyStackRef){.bits = 0xaaa0}; |
| entry.frame.f_locals = (PyObject*)0xaaa1; |
| entry.frame.frame_obj = (PyFrameObject*)0xaaa2; |
| entry.frame.f_globals = (PyObject*)0xaaa3; |
| entry.frame.f_builtins = (PyObject*)0xaaa4; |
| #endif |
| entry.frame.f_executable = PyStackRef_None; |
| entry.frame.instr_ptr = (_Py_CODEUNIT *)_Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR + 1; |
| entry.frame.stackpointer = entry.stack; |
| entry.frame.owner = FRAME_OWNED_BY_INTERPRETER; |
| entry.frame.visited = 0; |
| entry.frame.return_offset = 0; |
| #ifdef Py_DEBUG |
| entry.frame.lltrace = 0; |
| #endif |
| /* Push frame */ |
| entry.frame.previous = tstate->current_frame; |
| frame->previous = &entry.frame; |
| tstate->current_frame = frame; |
| entry.frame.localsplus[0] = PyStackRef_NULL; |
| |
| /* support for generator.throw() */ |
| if (throwflag) { |
| if (_Py_EnterRecursivePy(tstate)) { |
| goto early_exit; |
| } |
| #ifdef Py_GIL_DISABLED |
| /* Load thread-local bytecode */ |
| if (frame->tlbc_index != ((_PyThreadStateImpl *)tstate)->tlbc_index) { |
| _Py_CODEUNIT *bytecode = |
| _PyEval_GetExecutableCode(tstate, _PyFrame_GetCode(frame)); |
| if (bytecode == NULL) { |
| goto early_exit; |
| } |
| ptrdiff_t off = frame->instr_ptr - _PyFrame_GetBytecode(frame); |
| frame->tlbc_index = ((_PyThreadStateImpl *)tstate)->tlbc_index; |
| frame->instr_ptr = bytecode + off; |
| } |
| #endif |
| /* Because this avoids the RESUME, we need to update instrumentation */ |
| _Py_Instrument(_PyFrame_GetCode(frame), tstate->interp); |
| next_instr = frame->instr_ptr; |
| monitor_throw(tstate, frame, next_instr); |
| stack_pointer = _PyFrame_GetStackPointer(frame); |
| #if _Py_TAIL_CALL_INTERP |
| # if Py_STATS |
| return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, instruction_funcptr_handler_table, 0, lastopcode); |
| # else |
| return _TAIL_CALL_error(frame, stack_pointer, tstate, next_instr, instruction_funcptr_handler_table, 0); |
| # endif |
| #else |
| goto error; |
| #endif |
| } |
| |
| #if _Py_TAIL_CALL_INTERP |
| # if Py_STATS |
| return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, instruction_funcptr_handler_table, 0, lastopcode); |
| # else |
| return _TAIL_CALL_start_frame(frame, NULL, tstate, NULL, instruction_funcptr_handler_table, 0); |
| # endif |
| #else |
| goto start_frame; |
| #include "test_cases.c.h" |
| #endif |
| |
| |
| early_exit: |
| assert(_PyErr_Occurred(tstate)); |
| _Py_LeaveRecursiveCallPy(tstate); |
| assert(frame->owner != FRAME_OWNED_BY_INTERPRETER); |
| // GH-99729: We need to unlink the frame *before* clearing it: |
| _PyInterpreterFrame *dying = frame; |
| frame = tstate->current_frame = dying->previous; |
| _PyEval_FrameClearAndPop(tstate, dying); |
| frame->return_offset = 0; |
| assert(frame->owner == FRAME_OWNED_BY_INTERPRETER); |
| /* Restore previous frame and exit */ |
| tstate->current_frame = frame->previous; |
| return NULL; |
| } |