mirror of
https://github.com/python/cpython.git
synced 2026-01-24 16:18:45 +00:00
153 lines
4.8 KiB
C
153 lines
4.8 KiB
C
#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;
|
|
}
|