aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Python/ceval.c
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.com>2024-02-12 07:53:52 +0300
committerDaniil Cherednik <dcherednik@ydb.tech>2024-02-14 14:26:16 +0000
commit31f2a419764a8ba77c2a970cfc80056c6cd06756 (patch)
treec1995d239eba8571cefc640f6648e1d5dd4ce9e2 /contrib/tools/python3/src/Python/ceval.c
parentfe2ef02b38d9c85d80060963b265a1df9f38c3bb (diff)
downloadydb-31f2a419764a8ba77c2a970cfc80056c6cd06756.tar.gz
Update Python from 3.11.8 to 3.12.2
Diffstat (limited to 'contrib/tools/python3/src/Python/ceval.c')
-rw-r--r--contrib/tools/python3/src/Python/ceval.c6200
1 files changed, 522 insertions, 5678 deletions
diff --git a/contrib/tools/python3/src/Python/ceval.c b/contrib/tools/python3/src/Python/ceval.c
index 1ce6bbc10f..6110883ca0 100644
--- a/contrib/tools/python3/src/Python/ceval.c
+++ b/contrib/tools/python3/src/Python/ceval.c
@@ -1,9 +1,6 @@
/* Execute compiled code */
-/* XXX TO DO:
- XXX speed up searching for keywords by using a dictionary
- XXX document it!
- */
+#define _PY_INTERPRETER
#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
@@ -11,22 +8,26 @@
#include "pycore_ceval.h" // _PyEval_SignalAsyncExc()
#include "pycore_code.h"
#include "pycore_function.h"
-#include "pycore_initconfig.h" // _PyStatus_OK()
+#include "pycore_intrinsics.h"
#include "pycore_long.h" // _PyLong_GetZero()
+#include "pycore_instruments.h"
#include "pycore_object.h" // _PyObject_GC_TRACK()
#include "pycore_moduleobject.h" // PyModuleObject
#include "pycore_opcode.h" // EXTRA_CASES
-#include "pycore_pyerrors.h" // _PyErr_Fetch()
-#include "pycore_pylifecycle.h" // _PyErr_Print()
+#include "pycore_pyerrors.h" // _PyErr_GetRaisedException()
#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
+#include "pycore_range.h" // _PyRangeIterObject
+#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
#include "pycore_sysmodule.h" // _PySys_Audit()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
+#include "pycore_typeobject.h" // _PySuper_Lookup()
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
#include "pycore_dict.h"
#include "dictobject.h"
#include "pycore_frame.h"
+#include "frameobject.h" // _PyInterpreterFrame_GetLine
#include "opcode.h"
#include "pydtrace.h"
#include "setobject.h"
@@ -55,6 +56,10 @@
#define Py_DECREF(arg) \
do { \
PyObject *op = _PyObject_CAST(arg); \
+ if (_Py_IsImmortal(op)) { \
+ break; \
+ } \
+ _Py_DECREF_STAT_INC(); \
if (--op->ob_refcnt == 0) { \
destructor dealloc = Py_TYPE(op)->tp_dealloc; \
(*dealloc)(op); \
@@ -78,6 +83,10 @@
#define _Py_DECREF_SPECIALIZED(arg, dealloc) \
do { \
PyObject *op = _PyObject_CAST(arg); \
+ if (_Py_IsImmortal(op)) { \
+ break; \
+ } \
+ _Py_DECREF_STAT_INC(); \
if (--op->ob_refcnt == 0) { \
destructor d = (destructor)(dealloc); \
d(op); \
@@ -93,21 +102,12 @@
#endif
-/* Forward declarations */
-static PyObject *trace_call_function(
- PyThreadState *tstate, PyObject *callable, PyObject **stack,
- Py_ssize_t oparg, PyObject *kwnames);
-static PyObject * do_call_core(
- PyThreadState *tstate, PyObject *func,
- PyObject *callargs, PyObject *kwdict, int use_tracing);
-
#ifdef LLTRACE
static void
dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer)
{
PyObject **stack_base = _PyFrame_Stackbase(frame);
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
+ PyObject *exc = PyErr_GetRaisedException();
printf(" stack=[");
for (PyObject **ptr = stack_base; ptr < stack_pointer; ptr++) {
if (ptr != stack_base) {
@@ -121,7 +121,7 @@ dump_stack(_PyInterpreterFrame *frame, PyObject **stack_pointer)
}
printf("]\n");
fflush(stdout);
- PyErr_Restore(type, value, traceback);
+ PyErr_SetRaisedException(exc);
}
static void
@@ -129,13 +129,16 @@ lltrace_instruction(_PyInterpreterFrame *frame,
PyObject **stack_pointer,
_Py_CODEUNIT *next_instr)
{
+ /* This dump_stack() operation is risky, since the repr() of some
+ objects enters the interpreter recursively. It is also slow.
+ So you might want to comment it out. */
dump_stack(frame, stack_pointer);
- int oparg = _Py_OPARG(*next_instr);
- int opcode = _Py_OPCODE(*next_instr);
+ int oparg = next_instr->op.arg;
+ int opcode = next_instr->op.code;
const char *opname = _PyOpcode_OpName[opcode];
assert(opname != NULL);
int offset = (int)(next_instr - _PyCode_CODE(frame->f_code));
- if (HAS_ARG(opcode)) {
+ if (HAS_ARG((int)_PyOpcode_Deopt[opcode])) {
printf("%d: %s %d\n", offset * 2, opname, oparg);
}
else {
@@ -146,13 +149,16 @@ lltrace_instruction(_PyInterpreterFrame *frame,
static void
lltrace_resume_frame(_PyInterpreterFrame *frame)
{
- PyFunctionObject *f = frame->f_func;
- if (f == NULL) {
- printf("\nResuming frame.");
+ PyObject *fobj = frame->f_funcobj;
+ if (frame->owner == FRAME_OWNED_BY_CSTACK ||
+ fobj == NULL ||
+ !PyFunction_Check(fobj)
+ ) {
+ printf("\nResuming frame.\n");
return;
}
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
+ PyFunctionObject *f = (PyFunctionObject *)fobj;
+ PyObject *exc = PyErr_GetRaisedException();
PyObject *name = f->func_qualname;
if (name == NULL) {
name = f->func_name;
@@ -172,27 +178,32 @@ lltrace_resume_frame(_PyInterpreterFrame *frame)
}
printf("\n");
fflush(stdout);
- PyErr_Restore(type, value, traceback);
+ PyErr_SetRaisedException(exc);
}
#endif
-static int call_trace(Py_tracefunc, PyObject *,
- PyThreadState *, _PyInterpreterFrame *,
- int, PyObject *);
-static int call_trace_protected(Py_tracefunc, PyObject *,
- PyThreadState *, _PyInterpreterFrame *,
- int, PyObject *);
-static void call_exc_trace(Py_tracefunc, PyObject *,
- PyThreadState *, _PyInterpreterFrame *);
-static int maybe_call_line_trace(Py_tracefunc, PyObject *,
- PyThreadState *, _PyInterpreterFrame *, int);
-static void maybe_dtrace_line(_PyInterpreterFrame *, PyTraceInfo *, int);
-static void dtrace_function_entry(_PyInterpreterFrame *);
-static void dtrace_function_return(_PyInterpreterFrame *);
+
+static void monitor_raise(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr);
+static void monitor_reraise(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr);
+static int monitor_stop_iteration(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr);
+static void monitor_unwind(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr);
+static int monitor_handled(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr, PyObject *exc);
+static void monitor_throw(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr);
static PyObject * import_name(PyThreadState *, _PyInterpreterFrame *,
PyObject *, PyObject *, PyObject *);
static PyObject * import_from(PyThreadState *, PyObject *, PyObject *);
-static int import_all_from(PyThreadState *, PyObject *, PyObject *);
static void format_exc_check_arg(PyThreadState *, PyObject *, const char *, PyObject *);
static void format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg);
static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg);
@@ -205,594 +216,21 @@ static _PyInterpreterFrame *
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
PyObject *locals, PyObject* const* args,
size_t argcount, PyObject *kwnames);
+static _PyInterpreterFrame *
+_PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
+ PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs);
static void
_PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame);
-#define NAME_ERROR_MSG \
- "name '%.200s' is not defined"
#define UNBOUNDLOCAL_ERROR_MSG \
"cannot access local variable '%s' where it is not associated with a value"
#define UNBOUNDFREE_ERROR_MSG \
"cannot access free variable '%s' where it is not associated with a" \
" value in enclosing scope"
-
-/* This can set eval_breaker to 0 even though gil_drop_request became
- 1. We believe this is all right because the eval loop will release
- the GIL eventually anyway. */
-static inline void
-COMPUTE_EVAL_BREAKER(PyInterpreterState *interp,
- struct _ceval_runtime_state *ceval,
- struct _ceval_state *ceval2)
-{
- _Py_atomic_store_relaxed(&ceval2->eval_breaker,
- _Py_atomic_load_relaxed_int32(&ceval2->gil_drop_request)
- | (_Py_atomic_load_relaxed_int32(&ceval->signals_pending)
- && _Py_ThreadCanHandleSignals(interp))
- | (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do)
- && _Py_ThreadCanHandlePendingCalls())
- | ceval2->pending.async_exc);
-}
-
-
-static inline void
-SET_GIL_DROP_REQUEST(PyInterpreterState *interp)
-{
- struct _ceval_state *ceval2 = &interp->ceval;
- _Py_atomic_store_relaxed(&ceval2->gil_drop_request, 1);
- _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1);
-}
-
-
-static inline void
-RESET_GIL_DROP_REQUEST(PyInterpreterState *interp)
-{
- struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
- struct _ceval_state *ceval2 = &interp->ceval;
- _Py_atomic_store_relaxed(&ceval2->gil_drop_request, 0);
- COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
-}
-
-
-static inline void
-SIGNAL_PENDING_CALLS(PyInterpreterState *interp)
-{
- struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
- struct _ceval_state *ceval2 = &interp->ceval;
- _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 1);
- COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
-}
-
-
-static inline void
-UNSIGNAL_PENDING_CALLS(PyInterpreterState *interp)
-{
- struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
- struct _ceval_state *ceval2 = &interp->ceval;
- _Py_atomic_store_relaxed(&ceval2->pending.calls_to_do, 0);
- COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
-}
-
-
-static inline void
-SIGNAL_PENDING_SIGNALS(PyInterpreterState *interp, int force)
-{
- struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
- struct _ceval_state *ceval2 = &interp->ceval;
- _Py_atomic_store_relaxed(&ceval->signals_pending, 1);
- if (force) {
- _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1);
- }
- else {
- /* eval_breaker is not set to 1 if thread_can_handle_signals() is false */
- COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
- }
-}
-
-
-static inline void
-UNSIGNAL_PENDING_SIGNALS(PyInterpreterState *interp)
-{
- struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
- struct _ceval_state *ceval2 = &interp->ceval;
- _Py_atomic_store_relaxed(&ceval->signals_pending, 0);
- COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
-}
-
-
-static inline void
-SIGNAL_ASYNC_EXC(PyInterpreterState *interp)
-{
- struct _ceval_state *ceval2 = &interp->ceval;
- ceval2->pending.async_exc = 1;
- _Py_atomic_store_relaxed(&ceval2->eval_breaker, 1);
-}
-
-
-static inline void
-UNSIGNAL_ASYNC_EXC(PyInterpreterState *interp)
-{
- struct _ceval_runtime_state *ceval = &interp->runtime->ceval;
- struct _ceval_state *ceval2 = &interp->ceval;
- ceval2->pending.async_exc = 0;
- COMPUTE_EVAL_BREAKER(interp, ceval, ceval2);
-}
-
-
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
-#include "ceval_gil.h"
-
-void _Py_NO_RETURN
-_Py_FatalError_TstateNULL(const char *func)
-{
- _Py_FatalErrorFunc(func,
- "the function must be called with the GIL held, "
- "but the GIL is released "
- "(the current Python thread state is NULL)");
-}
-
-int
-_PyEval_ThreadsInitialized(_PyRuntimeState *runtime)
-{
- return gil_created(&runtime->ceval.gil);
-}
-
-int
-PyEval_ThreadsInitialized(void)
-{
- _PyRuntimeState *runtime = &_PyRuntime;
- return _PyEval_ThreadsInitialized(runtime);
-}
-
-PyStatus
-_PyEval_InitGIL(PyThreadState *tstate)
-{
- if (!_Py_IsMainInterpreter(tstate->interp)) {
- /* Currently, the GIL is shared by all interpreters,
- and only the main interpreter is responsible to create
- and destroy it. */
- return _PyStatus_OK();
- }
-
- struct _gil_runtime_state *gil = &tstate->interp->runtime->ceval.gil;
- assert(!gil_created(gil));
-
- PyThread_init_thread();
- create_gil(gil);
-
- take_gil(tstate);
-
- assert(gil_created(gil));
- return _PyStatus_OK();
-}
-
-void
-_PyEval_FiniGIL(PyInterpreterState *interp)
-{
- if (!_Py_IsMainInterpreter(interp)) {
- /* Currently, the GIL is shared by all interpreters,
- and only the main interpreter is responsible to create
- and destroy it. */
- return;
- }
-
- struct _gil_runtime_state *gil = &interp->runtime->ceval.gil;
- if (!gil_created(gil)) {
- /* First Py_InitializeFromConfig() call: the GIL doesn't exist
- yet: do nothing. */
- return;
- }
-
- destroy_gil(gil);
- assert(!gil_created(gil));
-}
-
-void
-PyEval_InitThreads(void)
-{
- /* Do nothing: kept for backward compatibility */
-}
-
-void
-_PyEval_Fini(void)
-{
-#ifdef Py_STATS
- _Py_PrintSpecializationStats(1);
-#endif
-}
-
-void
-PyEval_AcquireLock(void)
-{
- _PyRuntimeState *runtime = &_PyRuntime;
- PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
- _Py_EnsureTstateNotNULL(tstate);
-
- take_gil(tstate);
-}
-
-void
-PyEval_ReleaseLock(void)
-{
- _PyRuntimeState *runtime = &_PyRuntime;
- PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime);
- /* This function must succeed when the current thread state is NULL.
- We therefore avoid PyThreadState_Get() which dumps a fatal error
- in debug mode. */
- struct _ceval_runtime_state *ceval = &runtime->ceval;
- struct _ceval_state *ceval2 = &tstate->interp->ceval;
- drop_gil(ceval, ceval2, tstate);
-}
-
-void
-_PyEval_ReleaseLock(PyThreadState *tstate)
-{
- struct _ceval_runtime_state *ceval = &tstate->interp->runtime->ceval;
- struct _ceval_state *ceval2 = &tstate->interp->ceval;
- drop_gil(ceval, ceval2, tstate);
-}
-
-void
-PyEval_AcquireThread(PyThreadState *tstate)
-{
- _Py_EnsureTstateNotNULL(tstate);
-
- take_gil(tstate);
-
- struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
- if (_PyThreadState_Swap(gilstate, tstate) != NULL) {
- Py_FatalError("non-NULL old thread state");
- }
-}
-
-void
-PyEval_ReleaseThread(PyThreadState *tstate)
-{
- assert(_PyThreadState_CheckConsistency(tstate));
-
- _PyRuntimeState *runtime = tstate->interp->runtime;
- PyThreadState *new_tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
- if (new_tstate != tstate) {
- Py_FatalError("wrong thread state");
- }
- struct _ceval_runtime_state *ceval = &runtime->ceval;
- struct _ceval_state *ceval2 = &tstate->interp->ceval;
- drop_gil(ceval, ceval2, tstate);
-}
-
-#ifdef HAVE_FORK
-/* This function is called from PyOS_AfterFork_Child to destroy all threads
- which are not running in the child process, and clear internal locks
- which might be held by those threads. */
-PyStatus
-_PyEval_ReInitThreads(PyThreadState *tstate)
-{
- _PyRuntimeState *runtime = tstate->interp->runtime;
-
- struct _gil_runtime_state *gil = &runtime->ceval.gil;
- if (!gil_created(gil)) {
- return _PyStatus_OK();
- }
- recreate_gil(gil);
-
- take_gil(tstate);
-
- struct _pending_calls *pending = &tstate->interp->ceval.pending;
- if (_PyThread_at_fork_reinit(&pending->lock) < 0) {
- return _PyStatus_ERR("Can't reinitialize pending calls lock");
- }
-
- /* Destroy all threads except the current one */
- _PyThreadState_DeleteExcept(runtime, tstate);
- return _PyStatus_OK();
-}
-#endif
-
-/* This function is used to signal that async exceptions are waiting to be
- raised. */
-
-void
-_PyEval_SignalAsyncExc(PyInterpreterState *interp)
-{
- SIGNAL_ASYNC_EXC(interp);
-}
-
-PyThreadState *
-PyEval_SaveThread(void)
-{
- _PyRuntimeState *runtime = &_PyRuntime;
- PyThreadState *tstate = _PyThreadState_Swap(&runtime->gilstate, NULL);
- _Py_EnsureTstateNotNULL(tstate);
-
- struct _ceval_runtime_state *ceval = &runtime->ceval;
- struct _ceval_state *ceval2 = &tstate->interp->ceval;
- assert(gil_created(&ceval->gil));
- drop_gil(ceval, ceval2, tstate);
- return tstate;
-}
-
-void
-PyEval_RestoreThread(PyThreadState *tstate)
-{
- _Py_EnsureTstateNotNULL(tstate);
-
- take_gil(tstate);
-
- struct _gilstate_runtime_state *gilstate = &tstate->interp->runtime->gilstate;
- _PyThreadState_Swap(gilstate, tstate);
-}
-
-
-/* Mechanism whereby asynchronously executing callbacks (e.g. UNIX
- signal handlers or Mac I/O completion routines) can schedule calls
- to a function to be called synchronously.
- The synchronous function is called with one void* argument.
- It should return 0 for success or -1 for failure -- failure should
- be accompanied by an exception.
-
- If registry succeeds, the registry function returns 0; if it fails
- (e.g. due to too many pending calls) it returns -1 (without setting
- an exception condition).
-
- Note that because registry may occur from within signal handlers,
- or other asynchronous events, calling malloc() is unsafe!
-
- Any thread can schedule pending calls, but only the main thread
- will execute them.
- There is no facility to schedule calls to a particular thread, but
- that should be easy to change, should that ever be required. In
- that case, the static variables here should go into the python
- threadstate.
-*/
-
-void
-_PyEval_SignalReceived(PyInterpreterState *interp)
-{
-#ifdef MS_WINDOWS
- // bpo-42296: On Windows, _PyEval_SignalReceived() is called from a signal
- // handler which can run in a thread different than the Python thread, in
- // which case _Py_ThreadCanHandleSignals() is wrong. Ignore
- // _Py_ThreadCanHandleSignals() and always set eval_breaker to 1.
- //
- // The next eval_frame_handle_pending() call will call
- // _Py_ThreadCanHandleSignals() to recompute eval_breaker.
- int force = 1;
-#else
- int force = 0;
-#endif
- /* bpo-30703: Function called when the C signal handler of Python gets a
- signal. We cannot queue a callback using _PyEval_AddPendingCall() since
- that function is not async-signal-safe. */
- SIGNAL_PENDING_SIGNALS(interp, force);
-}
-
-/* Push one item onto the queue while holding the lock. */
-static int
-_push_pending_call(struct _pending_calls *pending,
- int (*func)(void *), void *arg)
-{
- int i = pending->last;
- int j = (i + 1) % NPENDINGCALLS;
- if (j == pending->first) {
- return -1; /* Queue full */
- }
- pending->calls[i].func = func;
- pending->calls[i].arg = arg;
- pending->last = j;
- return 0;
-}
-
-/* Pop one item off the queue while holding the lock. */
-static void
-_pop_pending_call(struct _pending_calls *pending,
- int (**func)(void *), void **arg)
-{
- int i = pending->first;
- if (i == pending->last) {
- return; /* Queue empty */
- }
-
- *func = pending->calls[i].func;
- *arg = pending->calls[i].arg;
- pending->first = (i + 1) % NPENDINGCALLS;
-}
-
-/* This implementation is thread-safe. It allows
- scheduling to be made from any thread, and even from an executing
- callback.
- */
-
-int
-_PyEval_AddPendingCall(PyInterpreterState *interp,
- int (*func)(void *), void *arg)
-{
- struct _pending_calls *pending = &interp->ceval.pending;
-
- /* Ensure that _PyEval_InitPendingCalls() was called
- and that _PyEval_FiniPendingCalls() is not called yet. */
- assert(pending->lock != NULL);
-
- PyThread_acquire_lock(pending->lock, WAIT_LOCK);
- int result = _push_pending_call(pending, func, arg);
- PyThread_release_lock(pending->lock);
-
- /* signal main loop */
- SIGNAL_PENDING_CALLS(interp);
- return result;
-}
-
-int
-Py_AddPendingCall(int (*func)(void *), void *arg)
-{
- /* Best-effort to support subinterpreters and calls with the GIL released.
-
- First attempt _PyThreadState_GET() since it supports subinterpreters.
-
- If the GIL is released, _PyThreadState_GET() returns NULL . In this
- case, use PyGILState_GetThisThreadState() which works even if the GIL
- is released.
-
- Sadly, PyGILState_GetThisThreadState() doesn't support subinterpreters:
- see bpo-10915 and bpo-15751.
-
- Py_AddPendingCall() doesn't require the caller to hold the GIL. */
- PyThreadState *tstate = _PyThreadState_GET();
- if (tstate == NULL) {
- tstate = PyGILState_GetThisThreadState();
- }
-
- PyInterpreterState *interp;
- if (tstate != NULL) {
- interp = tstate->interp;
- }
- else {
- /* Last resort: use the main interpreter */
- interp = _PyInterpreterState_Main();
- }
- return _PyEval_AddPendingCall(interp, func, arg);
-}
-
-static int
-handle_signals(PyThreadState *tstate)
-{
- assert(_PyThreadState_CheckConsistency(tstate));
- if (!_Py_ThreadCanHandleSignals(tstate->interp)) {
- return 0;
- }
-
- UNSIGNAL_PENDING_SIGNALS(tstate->interp);
- if (_PyErr_CheckSignalsTstate(tstate) < 0) {
- /* On failure, re-schedule a call to handle_signals(). */
- SIGNAL_PENDING_SIGNALS(tstate->interp, 0);
- return -1;
- }
- return 0;
-}
-
-static int
-make_pending_calls(PyInterpreterState *interp)
-{
- /* only execute pending calls on main thread */
- if (!_Py_ThreadCanHandlePendingCalls()) {
- return 0;
- }
-
- /* don't perform recursive pending calls */
- static int busy = 0;
- if (busy) {
- return 0;
- }
- busy = 1;
-
- /* unsignal before starting to call callbacks, so that any callback
- added in-between re-signals */
- UNSIGNAL_PENDING_CALLS(interp);
- int res = 0;
-
- /* perform a bounded number of calls, in case of recursion */
- struct _pending_calls *pending = &interp->ceval.pending;
- for (int i=0; i<NPENDINGCALLS; i++) {
- int (*func)(void *) = NULL;
- void *arg = NULL;
-
- /* pop one item off the queue while holding the lock */
- PyThread_acquire_lock(pending->lock, WAIT_LOCK);
- _pop_pending_call(pending, &func, &arg);
- PyThread_release_lock(pending->lock);
-
- /* having released the lock, perform the callback */
- if (func == NULL) {
- break;
- }
- res = func(arg);
- if (res) {
- goto error;
- }
- }
-
- busy = 0;
- return res;
-
-error:
- busy = 0;
- SIGNAL_PENDING_CALLS(interp);
- return res;
-}
-
-void
-_Py_FinishPendingCalls(PyThreadState *tstate)
-{
- assert(PyGILState_Check());
- assert(_PyThreadState_CheckConsistency(tstate));
-
- struct _pending_calls *pending = &tstate->interp->ceval.pending;
-
- if (!_Py_atomic_load_relaxed_int32(&(pending->calls_to_do))) {
- return;
- }
-
- if (make_pending_calls(tstate->interp) < 0) {
- PyObject *exc, *val, *tb;
- _PyErr_Fetch(tstate, &exc, &val, &tb);
- PyErr_BadInternalCall();
- _PyErr_ChainExceptions(exc, val, tb);
- _PyErr_Print(tstate);
- }
-}
-
-/* Py_MakePendingCalls() is a simple wrapper for the sake
- of backward-compatibility. */
-int
-Py_MakePendingCalls(void)
-{
- assert(PyGILState_Check());
-
- PyThreadState *tstate = _PyThreadState_GET();
- assert(_PyThreadState_CheckConsistency(tstate));
-
- /* Python signal handler doesn't really queue a callback: it only signals
- that a signal was received, see _PyEval_SignalReceived(). */
- int res = handle_signals(tstate);
- if (res != 0) {
- return res;
- }
-
- res = make_pending_calls(tstate->interp);
- if (res != 0) {
- return res;
- }
-
- return 0;
-}
-
-/* The interpreter's recursion limit */
-
-void
-_PyEval_InitRuntimeState(struct _ceval_runtime_state *ceval)
-{
- _gil_initialize(&ceval->gil);
-}
-
-void
-_PyEval_InitState(struct _ceval_state *ceval, PyThread_type_lock pending_lock)
-{
- struct _pending_calls *pending = &ceval->pending;
- assert(pending->lock == NULL);
-
- pending->lock = pending_lock;
-}
-
-void
-_PyEval_FiniState(struct _ceval_state *ceval)
-{
- struct _pending_calls *pending = &ceval->pending;
- if (pending->lock != NULL) {
- PyThread_free_lock(pending->lock);
- pending->lock = NULL;
- }
-}
int
Py_GetRecursionLimit(void)
@@ -807,9 +245,9 @@ Py_SetRecursionLimit(int new_limit)
PyInterpreterState *interp = _PyInterpreterState_GET();
interp->ceval.recursion_limit = new_limit;
for (PyThreadState *p = interp->threads.head; p != NULL; p = p->next) {
- int depth = p->recursion_limit - p->recursion_remaining;
- p->recursion_limit = new_limit;
- p->recursion_remaining = new_limit - depth;
+ int depth = p->py_recursion_limit - p->py_recursion_remaining;
+ p->py_recursion_limit = new_limit;
+ p->py_recursion_remaining = new_limit - depth;
}
}
@@ -818,35 +256,27 @@ Py_SetRecursionLimit(int new_limit)
int
_Py_CheckRecursiveCall(PyThreadState *tstate, const char *where)
{
- /* Check against global limit first. */
- int depth = tstate->recursion_limit - tstate->recursion_remaining;
- if (depth < tstate->interp->ceval.recursion_limit) {
- tstate->recursion_limit = tstate->interp->ceval.recursion_limit;
- tstate->recursion_remaining = tstate->recursion_limit - depth;
- assert(tstate->recursion_remaining > 0);
- return 0;
- }
#ifdef USE_STACKCHECK
if (PyOS_CheckStack()) {
- ++tstate->recursion_remaining;
+ ++tstate->c_recursion_remaining;
_PyErr_SetString(tstate, PyExc_MemoryError, "Stack overflow");
return -1;
}
#endif
if (tstate->recursion_headroom) {
- if (tstate->recursion_remaining < -50) {
+ if (tstate->c_recursion_remaining < -50) {
/* Overflowing while handling an overflow. Give up. */
Py_FatalError("Cannot recover from stack overflow.");
}
}
else {
- if (tstate->recursion_remaining <= 0) {
+ if (tstate->c_recursion_remaining <= 0) {
tstate->recursion_headroom++;
_PyErr_Format(tstate, PyExc_RecursionError,
"maximum recursion depth exceeded%s",
where);
tstate->recursion_headroom--;
- ++tstate->recursion_remaining;
+ ++tstate->c_recursion_remaining;
return -1;
}
}
@@ -949,8 +379,7 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys)
Py_DECREF(value);
Py_DECREF(values);
// Return None:
- Py_INCREF(Py_None);
- values = Py_None;
+ values = Py_NewRef(Py_None);
goto done;
}
PyTuple_SET_ITEM(values, i, value);
@@ -1001,7 +430,7 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type,
Py_ssize_t nargs, PyObject *kwargs)
{
if (!PyType_Check(type)) {
- const char *e = "called match pattern must be a type";
+ const char *e = "called match pattern must be a class";
_PyErr_Format(tstate, PyExc_TypeError, e);
return NULL;
}
@@ -1145,6 +574,7 @@ PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
if (func == NULL) {
return NULL;
}
+ EVAL_CALL_STAT_INC(EVAL_CALL_LEGACY);
PyObject *res = _PyEval_Vector(tstate, func, locals, NULL, 0, NULL);
Py_DECREF(func);
return res;
@@ -1168,462 +598,57 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
return _PyEval_EvalFrame(tstate, f->f_frame, throwflag);
}
+#include "ceval_macros.h"
-/* Handle signals, pending calls, GIL drop request
- and asynchronous exception */
-static int
-eval_frame_handle_pending(PyThreadState *tstate)
-{
- _PyRuntimeState * const runtime = &_PyRuntime;
- struct _ceval_runtime_state *ceval = &runtime->ceval;
- /* Pending signals */
- if (_Py_atomic_load_relaxed_int32(&ceval->signals_pending)) {
- if (handle_signals(tstate) != 0) {
- return -1;
+int _Py_CheckRecursiveCallPy(
+ PyThreadState *tstate)
+{
+ if (tstate->recursion_headroom) {
+ if (tstate->py_recursion_remaining < -50) {
+ /* Overflowing while handling an overflow. Give up. */
+ Py_FatalError("Cannot recover from Python stack overflow.");
}
}
-
- /* Pending calls */
- struct _ceval_state *ceval2 = &tstate->interp->ceval;
- if (_Py_atomic_load_relaxed_int32(&ceval2->pending.calls_to_do)) {
- if (make_pending_calls(tstate->interp) != 0) {
+ else {
+ if (tstate->py_recursion_remaining <= 0) {
+ tstate->recursion_headroom++;
+ _PyErr_Format(tstate, PyExc_RecursionError,
+ "maximum recursion depth exceeded");
+ tstate->recursion_headroom--;
return -1;
}
}
-
- /* GIL drop request */
- if (_Py_atomic_load_relaxed_int32(&ceval2->gil_drop_request)) {
- /* Give another thread a chance */
- if (_PyThreadState_Swap(&runtime->gilstate, NULL) != tstate) {
- Py_FatalError("tstate mix-up");
- }
- drop_gil(ceval, ceval2, tstate);
-
- /* Other threads may run now */
-
- take_gil(tstate);
-
- if (_PyThreadState_Swap(&runtime->gilstate, tstate) != NULL) {
- Py_FatalError("orphan tstate");
- }
- }
-
- /* Check for asynchronous exception. */
- if (tstate->async_exc != NULL) {
- PyObject *exc = tstate->async_exc;
- tstate->async_exc = NULL;
- UNSIGNAL_ASYNC_EXC(tstate->interp);
- _PyErr_SetNone(tstate, exc);
- Py_DECREF(exc);
- return -1;
- }
-
-#ifdef MS_WINDOWS
- // bpo-42296: On Windows, _PyEval_SignalReceived() can be called in a
- // different thread than the Python thread, in which case
- // _Py_ThreadCanHandleSignals() is wrong. Recompute eval_breaker in the
- // current Python thread with the correct _Py_ThreadCanHandleSignals()
- // value. It prevents to interrupt the eval loop at every instruction if
- // the current Python thread cannot handle signals (if
- // _Py_ThreadCanHandleSignals() is false).
- COMPUTE_EVAL_BREAKER(tstate->interp, ceval, ceval2);
-#endif
-
return 0;
}
+static inline int _Py_EnterRecursivePy(PyThreadState *tstate) {
+ return (tstate->py_recursion_remaining-- <= 0) &&
+ _Py_CheckRecursiveCallPy(tstate);
+}
-/* Computed GOTOs, or
- the-optimization-commonly-but-improperly-known-as-"threaded code"
- using gcc's labels-as-values extension
- (http://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html).
-
- The traditional bytecode evaluation loop uses a "switch" statement, which
- decent compilers will optimize as a single indirect branch instruction
- combined with a lookup table of jump addresses. However, since the
- indirect jump instruction is shared by all opcodes, the CPU will have a
- hard time making the right prediction for where to jump next (actually,
- it will be always wrong except in the uncommon case of a sequence of
- several identical opcodes).
-
- "Threaded code" in contrast, uses an explicit jump table and an explicit
- indirect jump instruction at the end of each opcode. Since the jump
- instruction is at a different address for each opcode, the CPU will make a
- separate prediction for each of these instructions, which is equivalent to
- predicting the second opcode of each opcode pair. These predictions have
- a much better chance to turn out valid, especially in small bytecode loops.
-
- A mispredicted branch on a modern CPU flushes the whole pipeline and
- can cost several CPU cycles (depending on the pipeline depth),
- and potentially many more instructions (depending on the pipeline width).
- A correctly predicted branch, however, is nearly free.
-
- At the time of this writing, the "threaded code" version is up to 15-20%
- faster than the normal "switch" version, depending on the compiler and the
- CPU architecture.
-
- NOTE: care must be taken that the compiler doesn't try to "optimize" the
- indirect jumps by sharing them between all opcodes. Such optimizations
- can be disabled on gcc by using the -fno-gcse flag (or possibly
- -fno-crossjumping).
-*/
-
-/* Use macros rather than inline functions, to make it as clear as possible
- * to the C compiler that the tracing check is a simple test then branch.
- * We want to be sure that the compiler knows this before it generates
- * the CFG.
- */
-
-#ifdef WITH_DTRACE
-#define OR_DTRACE_LINE | (PyDTrace_LINE_ENABLED() ? 255 : 0)
-#else
-#define OR_DTRACE_LINE
-#endif
-
-#ifdef HAVE_COMPUTED_GOTOS
- #ifndef USE_COMPUTED_GOTOS
- #define USE_COMPUTED_GOTOS 1
- #endif
-#else
- #if defined(USE_COMPUTED_GOTOS) && USE_COMPUTED_GOTOS
- #error "Computed gotos are not supported on this compiler."
- #endif
- #undef USE_COMPUTED_GOTOS
- #define USE_COMPUTED_GOTOS 0
-#endif
-
-#ifdef Py_STATS
-#define INSTRUCTION_START(op) \
- do { \
- frame->prev_instr = next_instr++; \
- OPCODE_EXE_INC(op); \
- _py_stats.opcode_stats[lastopcode].pair_count[op]++; \
- lastopcode = op; \
- } while (0)
-#else
-#define INSTRUCTION_START(op) (frame->prev_instr = next_instr++)
-#endif
-
-#if USE_COMPUTED_GOTOS
-#define TARGET(op) TARGET_##op: INSTRUCTION_START(op);
-#define DISPATCH_GOTO() goto *opcode_targets[opcode]
-#else
-#define TARGET(op) case op: INSTRUCTION_START(op);
-#define DISPATCH_GOTO() goto dispatch_opcode
-#endif
-
-/* PRE_DISPATCH_GOTO() does lltrace if enabled. Normally a no-op */
-#ifdef LLTRACE
-#define PRE_DISPATCH_GOTO() if (lltrace) { \
- lltrace_instruction(frame, stack_pointer, next_instr); }
-#else
-#define PRE_DISPATCH_GOTO() ((void)0)
-#endif
-
-
-/* Do interpreter dispatch accounting for tracing and instrumentation */
-#define DISPATCH() \
- { \
- NEXTOPARG(); \
- PRE_DISPATCH_GOTO(); \
- assert(cframe.use_tracing == 0 || cframe.use_tracing == 255); \
- opcode |= cframe.use_tracing OR_DTRACE_LINE; \
- DISPATCH_GOTO(); \
- }
-
-#define DISPATCH_SAME_OPARG() \
- { \
- opcode = _Py_OPCODE(*next_instr); \
- PRE_DISPATCH_GOTO(); \
- opcode |= cframe.use_tracing OR_DTRACE_LINE; \
- DISPATCH_GOTO(); \
- }
-#define CHECK_EVAL_BREAKER() \
- _Py_CHECK_EMSCRIPTEN_SIGNALS_PERIODICALLY(); \
- if (_Py_atomic_load_relaxed_int32(eval_breaker)) { \
- goto handle_eval_breaker; \
- }
+static inline void _Py_LeaveRecursiveCallPy(PyThreadState *tstate) {
+ tstate->py_recursion_remaining++;
+}
-/* Tuple access macros */
+/* Disable unused label warnings. They are handy for debugging, even
+ if computed gotos aren't used. */
-#ifndef Py_DEBUG
-#define GETITEM(v, i) PyTuple_GET_ITEM((PyTupleObject *)(v), (i))
-#else
-#define GETITEM(v, i) PyTuple_GetItem((v), (i))
+/* TBD - what about other compilers? */
+#if defined(__GNUC__)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wunused-label"
+#elif defined(_MSC_VER) /* MS_WINDOWS */
+# pragma warning(push)
+# pragma warning(disable:4102)
#endif
-/* Code access macros */
-
-/* The integer overflow is checked by an assertion below. */
-#define INSTR_OFFSET() ((int)(next_instr - first_instr))
-#define NEXTOPARG() do { \
- _Py_CODEUNIT word = *next_instr; \
- opcode = _Py_OPCODE(word); \
- oparg = _Py_OPARG(word); \
- } while (0)
-#define JUMPTO(x) (next_instr = first_instr + (x))
-#define JUMPBY(x) (next_instr += (x))
-
-// Skip from a PRECALL over a CALL to the next instruction:
-#define SKIP_CALL() \
- JUMPBY(INLINE_CACHE_ENTRIES_PRECALL + 1 + INLINE_CACHE_ENTRIES_CALL)
-
-/* Get opcode and oparg from original instructions, not quickened form. */
-#define TRACING_NEXTOPARG() do { \
- NEXTOPARG(); \
- opcode = _PyOpcode_Deopt[opcode]; \
- } while (0)
-
-/* OpCode prediction macros
- Some opcodes tend to come in pairs thus making it possible to
- predict the second code when the first is run. For example,
- COMPARE_OP is often followed by POP_JUMP_IF_FALSE or POP_JUMP_IF_TRUE.
-
- Verifying the prediction costs a single high-speed test of a register
- variable against a constant. If the pairing was good, then the
- processor's own internal branch predication has a high likelihood of
- success, resulting in a nearly zero-overhead transition to the
- next opcode. A successful prediction saves a trip through the eval-loop
- including its unpredictable switch-case branch. Combined with the
- processor's internal branch prediction, a successful PREDICT has the
- effect of making the two opcodes run as if they were a single new opcode
- with the bodies combined.
-
- If collecting opcode statistics, your choices are to either keep the
- predictions turned-on and interpret the results as if some opcodes
- had been combined or turn-off predictions so that the opcode frequency
- counter updates for both opcodes.
-
- Opcode prediction is disabled with threaded code, since the latter allows
- the CPU to record separate branch prediction information for each
- opcode.
-
-*/
-
-#define PREDICT_ID(op) PRED_##op
-
-#if USE_COMPUTED_GOTOS
-#define PREDICT(op) if (0) goto PREDICT_ID(op)
-#else
-#define PREDICT(op) \
- do { \
- _Py_CODEUNIT word = *next_instr; \
- opcode = _Py_OPCODE(word) | cframe.use_tracing OR_DTRACE_LINE; \
- if (opcode == op) { \
- oparg = _Py_OPARG(word); \
- INSTRUCTION_START(op); \
- goto PREDICT_ID(op); \
- } \
- } while(0)
-#endif
-#define PREDICTED(op) PREDICT_ID(op):
-
-
-/* Stack manipulation macros */
-
-/* The stack can grow at most MAXINT deep, as co_nlocals and
- co_stacksize are ints. */
-#define STACK_LEVEL() ((int)(stack_pointer - _PyFrame_Stackbase(frame)))
-#define STACK_SIZE() (frame->f_code->co_stacksize)
-#define EMPTY() (STACK_LEVEL() == 0)
-#define TOP() (stack_pointer[-1])
-#define SECOND() (stack_pointer[-2])
-#define THIRD() (stack_pointer[-3])
-#define FOURTH() (stack_pointer[-4])
-#define PEEK(n) (stack_pointer[-(n)])
-#define SET_TOP(v) (stack_pointer[-1] = (v))
-#define SET_SECOND(v) (stack_pointer[-2] = (v))
-#define BASIC_STACKADJ(n) (stack_pointer += n)
-#define BASIC_PUSH(v) (*stack_pointer++ = (v))
-#define BASIC_POP() (*--stack_pointer)
-
-#ifdef Py_DEBUG
-#define PUSH(v) do { \
- BASIC_PUSH(v); \
- assert(STACK_LEVEL() <= STACK_SIZE()); \
- } while (0)
-#define POP() (assert(STACK_LEVEL() > 0), BASIC_POP())
-#define STACK_GROW(n) do { \
- assert(n >= 0); \
- BASIC_STACKADJ(n); \
- assert(STACK_LEVEL() <= STACK_SIZE()); \
- } while (0)
-#define STACK_SHRINK(n) do { \
- assert(n >= 0); \
- assert(STACK_LEVEL() >= n); \
- BASIC_STACKADJ(-(n)); \
- } while (0)
-#else
-#define PUSH(v) BASIC_PUSH(v)
-#define POP() BASIC_POP()
-#define STACK_GROW(n) BASIC_STACKADJ(n)
-#define STACK_SHRINK(n) BASIC_STACKADJ(-(n))
-#endif
-
-/* Local variable macros */
-
-#define GETLOCAL(i) (frame->localsplus[i])
-
-/* The SETLOCAL() macro must not DECREF the local variable in-place and
- then store the new value; it must copy the old value to a temporary
- value, then store the new value, and then DECREF the temporary value.
- This is because it is possible that during the DECREF the frame is
- accessed by other code (e.g. a __del__ method or gc.collect()) and the
- variable would be pointing to already-freed memory. */
-#define SETLOCAL(i, value) do { PyObject *tmp = GETLOCAL(i); \
- GETLOCAL(i) = value; \
- Py_XDECREF(tmp); } while (0)
-
-#define JUMP_TO_INSTRUCTION(op) goto PREDICT_ID(op)
-
-
-#define DEOPT_IF(cond, instname) if (cond) { goto miss; }
-
-
-#define GLOBALS() frame->f_globals
-#define BUILTINS() frame->f_builtins
-#define LOCALS() frame->f_locals
-
-/* Shared opcode macros */
-
-// shared by LOAD_ATTR_MODULE and LOAD_METHOD_MODULE
-#define LOAD_MODULE_ATTR_OR_METHOD(attr_or_method) \
- _PyAttrCache *cache = (_PyAttrCache *)next_instr; \
- DEOPT_IF(!PyModule_CheckExact(owner), LOAD_##attr_or_method); \
- PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict; \
- assert(dict != NULL); \
- DEOPT_IF(dict->ma_keys->dk_version != read_u32(cache->version), \
- LOAD_##attr_or_method); \
- assert(dict->ma_keys->dk_kind == DICT_KEYS_UNICODE); \
- assert(cache->index < dict->ma_keys->dk_nentries); \
- PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + cache->index; \
- res = ep->me_value; \
- DEOPT_IF(res == NULL, LOAD_##attr_or_method); \
- STAT_INC(LOAD_##attr_or_method, hit); \
- Py_INCREF(res);
-
-#define TRACE_FUNCTION_EXIT() \
- if (cframe.use_tracing) { \
- if (trace_function_exit(tstate, frame, retval)) { \
- Py_DECREF(retval); \
- goto exit_unwind; \
- } \
- }
-
-#define DTRACE_FUNCTION_EXIT() \
- if (PyDTrace_FUNCTION_RETURN_ENABLED()) { \
- dtrace_function_return(frame); \
- }
-
-#define TRACE_FUNCTION_UNWIND() \
- if (cframe.use_tracing) { \
- /* Since we are already unwinding, \
- * we don't care if this raises */ \
- trace_function_exit(tstate, frame, NULL); \
- }
-
-#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); \
- frame->stacktop = -1; \
- 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; \
- } \
- }
-
-#define DTRACE_FUNCTION_ENTRY() \
- if (PyDTrace_FUNCTION_ENTRY_ENABLED()) { \
- dtrace_function_entry(frame); \
- }
-
-#define ADAPTIVE_COUNTER_IS_ZERO(cache) \
- (cache)->counter < (1<<ADAPTIVE_BACKOFF_BITS)
-
-#define DECREMENT_ADAPTIVE_COUNTER(cache) \
- (cache)->counter -= (1<<ADAPTIVE_BACKOFF_BITS)
-
-static int
-trace_function_entry(PyThreadState *tstate, _PyInterpreterFrame *frame)
-{
- if (tstate->c_tracefunc != NULL) {
- /* tstate->c_tracefunc, if defined, is a
- function that will be called on *every* entry
- to a code block. Its return value, if not
- None, is a function that will be called at
- the start of each executed line of code.
- (Actually, the function must return itself
- in order to continue tracing.) The trace
- functions are called with three arguments:
- a pointer to the current frame, a string
- indicating why the function is called, and
- an argument which depends on the situation.
- The global trace function is also called
- whenever an exception is detected. */
- if (call_trace_protected(tstate->c_tracefunc,
- tstate->c_traceobj,
- tstate, frame,
- PyTrace_CALL, Py_None)) {
- /* Trace function raised an error */
- return -1;
- }
- }
- if (tstate->c_profilefunc != NULL) {
- /* Similar for c_profilefunc, except it needn't
- return itself and isn't called for "line" events */
- if (call_trace_protected(tstate->c_profilefunc,
- tstate->c_profileobj,
- tstate, frame,
- PyTrace_CALL, Py_None)) {
- /* Profile function raised an error */
- return -1;
- }
- }
- return 0;
-}
-
-static int
-trace_function_exit(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *retval)
-{
- if (tstate->c_tracefunc) {
- if (call_trace_protected(tstate->c_tracefunc, tstate->c_traceobj,
- tstate, frame, PyTrace_RETURN, retval)) {
- return -1;
- }
- }
- if (tstate->c_profilefunc) {
- if (call_trace_protected(tstate->c_profilefunc, tstate->c_profileobj,
- tstate, frame, PyTrace_RETURN, retval)) {
- return -1;
- }
- }
- return 0;
-}
-
-/* It is only between the PRECALL instruction and the following CALL,
- * that this has any meaning.
- */
-typedef struct {
- PyObject *kwnames;
-} CallShape;
-// GH-89279: Must be a macro to be sure it's inlined by MSVC.
-#define is_method(stack_pointer, args) (PEEK((args)+2) != NULL)
-
-#define KWNAMES_LEN() \
- (call_shape.kwnames == NULL ? 0 : ((int)PyTuple_GET_SIZE(call_shape.kwnames)))
+/* _PyEval_EvalFrameDefault() is a *big* function,
+ * so consume 3 units of C stack */
+#define PY_EVAL_C_STACK_UNITS 2
PyObject* _Py_HOT_FUNCTION
_PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int throwflag)
@@ -1643,73 +668,77 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
// for the big switch below (in combination with the EXTRA_CASES macro).
uint8_t opcode; /* Current opcode */
int oparg; /* Current opcode argument, if any */
- _Py_atomic_int * const eval_breaker = &tstate->interp->ceval.eval_breaker;
#ifdef LLTRACE
int lltrace = 0;
#endif
_PyCFrame cframe;
- CallShape call_shape;
- call_shape.kwnames = NULL; // Borrowed reference. Reset by CALL instructions.
+ _PyInterpreterFrame entry_frame;
+ PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions.
/* WARNING: Because the _PyCFrame lives on the C stack,
* but can be accessed from a heap allocated object (tstate)
* strict stack discipline must be maintained.
*/
_PyCFrame *prev_cframe = tstate->cframe;
- cframe.use_tracing = prev_cframe->use_tracing;
cframe.previous = prev_cframe;
tstate->cframe = &cframe;
- frame->is_entry = true;
+ assert(tstate->interp->interpreter_trampoline != NULL);
+#ifdef Py_DEBUG
+ /* Set these to invalid but identifiable values for debugging. */
+ entry_frame.f_funcobj = (PyObject*)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_code = tstate->interp->interpreter_trampoline;
+ entry_frame.prev_instr =
+ _PyCode_CODE(tstate->interp->interpreter_trampoline);
+ entry_frame.stacktop = 0;
+ entry_frame.owner = FRAME_OWNED_BY_CSTACK;
+ entry_frame.return_offset = 0;
/* Push frame */
- frame->previous = prev_cframe->current_frame;
+ entry_frame.previous = prev_cframe->current_frame;
+ frame->previous = &entry_frame;
cframe.current_frame = frame;
+ tstate->c_recursion_remaining -= (PY_EVAL_C_STACK_UNITS - 1);
+ if (_Py_EnterRecursiveCallTstate(tstate, "")) {
+ tstate->c_recursion_remaining--;
+ tstate->py_recursion_remaining--;
+ goto exit_unwind;
+ }
+
/* support for generator.throw() */
if (throwflag) {
- if (_Py_EnterRecursiveCallTstate(tstate, "")) {
- tstate->recursion_remaining--;
+ if (_Py_EnterRecursivePy(tstate)) {
goto exit_unwind;
}
- TRACE_FUNCTION_THROW_ENTRY();
- DTRACE_FUNCTION_ENTRY();
+ /* Because this avoids the RESUME,
+ * we need to update instrumentation */
+ _Py_Instrument(frame->f_code, tstate->interp);
+ monitor_throw(tstate, frame, frame->prev_instr);
+ /* TO DO -- Monitor throw entry. */
goto resume_with_error;
}
/* Local "register" variables.
* These are cached values from the frame and code object. */
- PyObject *names;
- PyObject *consts;
- _Py_CODEUNIT *first_instr;
_Py_CODEUNIT *next_instr;
PyObject **stack_pointer;
/* Sets the above local variables from the frame */
#define SET_LOCALS_FROM_FRAME() \
- { \
- PyCodeObject *co = frame->f_code; \
- names = co->co_names; \
- consts = co->co_consts; \
- first_instr = _PyCode_CODE(co); \
- } \
assert(_PyInterpreterFrame_LASTI(frame) >= -1); \
/* Jump back to the last instruction executed... */ \
next_instr = frame->prev_instr + 1; \
- stack_pointer = _PyFrame_GetStackPointer(frame); \
- /* Set stackdepth to -1. \
- Update when returning or calling trace function. \
- Having stackdepth <= 0 ensures that invalid \
- values are not visible to the cycle GC. \
- We choose -1 rather than 0 to assist debugging. \
- */ \
- frame->stacktop = -1;
-
+ stack_pointer = _PyFrame_GetStackPointer(frame);
start_frame:
- if (_Py_EnterRecursiveCallTstate(tstate, "")) {
- tstate->recursion_remaining--;
+ if (_Py_EnterRecursivePy(tstate)) {
goto exit_unwind;
}
@@ -1718,14 +747,16 @@ resume_frame:
#ifdef LLTRACE
{
- int r = PyDict_Contains(GLOBALS(), &_Py_ID(__lltrace__));
- if (r < 0) {
- goto exit_unwind;
+ if (frame != &entry_frame) {
+ int r = PyDict_Contains(GLOBALS(), &_Py_ID(__lltrace__));
+ if (r < 0) {
+ goto exit_unwind;
+ }
+ lltrace = r;
+ }
+ if (lltrace) {
+ lltrace_resume_frame(frame);
}
- lltrace = r;
- }
- if (lltrace) {
- lltrace_resume_frame(frame);
}
#endif
@@ -1744,3936 +775,112 @@ handle_eval_breaker:
* We need to do reasonably frequently, but not too frequently.
* All loops should include a check of the eval breaker.
* We also check on return from any builtin function.
+ *
+ * ## More Details ###
+ *
+ * The eval loop (this function) normally executes the instructions
+ * of a code object sequentially. However, the runtime supports a
+ * number of out-of-band execution scenarios that may pause that
+ * sequential execution long enough to do that out-of-band work
+ * in the current thread using the current PyThreadState.
+ *
+ * The scenarios include:
+ *
+ * - cyclic garbage collection
+ * - GIL drop requests
+ * - "async" exceptions
+ * - "pending calls" (some only in the main thread)
+ * - signal handling (only in the main thread)
+ *
+ * When the need for one of the above is detected, the eval loop
+ * pauses long enough to handle the detected case. Then, if doing
+ * so didn't trigger an exception, the eval loop resumes executing
+ * the sequential instructions.
+ *
+ * To make this work, the eval loop periodically checks if any
+ * of the above needs to happen. The individual checks can be
+ * expensive if computed each time, so a while back we switched
+ * to using pre-computed, per-interpreter variables for the checks,
+ * and later consolidated that to a single "eval breaker" variable
+ * (now a PyInterpreterState field).
+ *
+ * For the longest time, the eval breaker check would happen
+ * frequently, every 5 or so times through the loop, regardless
+ * of what instruction ran last or what would run next. Then, in
+ * early 2021 (gh-18334, commit 4958f5d), we switched to checking
+ * the eval breaker less frequently, by hard-coding the check to
+ * specific places in the eval loop (e.g. certain instructions).
+ * The intent then was to check after returning from calls
+ * and on the back edges of loops.
+ *
+ * In addition to being more efficient, that approach keeps
+ * the eval loop from running arbitrary code between instructions
+ * that don't handle that well. (See gh-74174.)
+ *
+ * Currently, the eval breaker check happens here at the
+ * "handle_eval_breaker" label. Some instructions come here
+ * explicitly (goto) and some indirectly. Notably, the check
+ * happens on back edges in the control flow graph, which
+ * pretty much applies to all loops and most calls.
+ * (See bytecodes.c for exact information.)
+ *
+ * One consequence of this approach is that it might not be obvious
+ * how to force any specific thread to pick up the eval breaker,
+ * or for any specific thread to not pick it up. Mostly this
+ * involves judicious uses of locks and careful ordering of code,
+ * while avoiding code that might trigger the eval breaker
+ * until so desired.
*/
- if (eval_frame_handle_pending(tstate) != 0) {
+ if (_Py_HandlePending(tstate) != 0) {
goto error;
}
DISPATCH();
{
/* Start instructions */
-#if USE_COMPUTED_GOTOS
- {
-#else
+#if !USE_COMPUTED_GOTOS
dispatch_opcode:
- switch (opcode) {
-#endif
-
- /* BEWARE!
- It is essential that any operation that fails must goto error
- and that all operation that succeed call DISPATCH() ! */
-
- TARGET(NOP) {
- DISPATCH();
- }
-
- TARGET(RESUME) {
- _PyCode_Warmup(frame->f_code);
- JUMP_TO_INSTRUCTION(RESUME_QUICK);
- }
-
- TARGET(RESUME_QUICK) {
- PREDICTED(RESUME_QUICK);
- assert(tstate->cframe == &cframe);
- assert(frame == cframe.current_frame);
- if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) {
- goto handle_eval_breaker;
- }
- DISPATCH();
- }
-
- TARGET(LOAD_CLOSURE) {
- /* We keep LOAD_CLOSURE so that the bytecode stays more readable. */
- PyObject *value = GETLOCAL(oparg);
- if (value == NULL) {
- goto unbound_local_error;
- }
- Py_INCREF(value);
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(LOAD_FAST) {
- PyObject *value = GETLOCAL(oparg);
- if (value == NULL) {
- goto unbound_local_error;
- }
- Py_INCREF(value);
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(LOAD_CONST) {
- PREDICTED(LOAD_CONST);
- PyObject *value = GETITEM(consts, oparg);
- Py_INCREF(value);
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(STORE_FAST) {
- PREDICTED(STORE_FAST);
- PyObject *value = POP();
- SETLOCAL(oparg, value);
- DISPATCH();
- }
-
- TARGET(LOAD_FAST__LOAD_FAST) {
- PyObject *value = GETLOCAL(oparg);
- if (value == NULL) {
- goto unbound_local_error;
- }
- NEXTOPARG();
- next_instr++;
- Py_INCREF(value);
- PUSH(value);
- value = GETLOCAL(oparg);
- if (value == NULL) {
- goto unbound_local_error;
- }
- Py_INCREF(value);
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(LOAD_FAST__LOAD_CONST) {
- PyObject *value = GETLOCAL(oparg);
- if (value == NULL) {
- goto unbound_local_error;
- }
- NEXTOPARG();
- next_instr++;
- Py_INCREF(value);
- PUSH(value);
- value = GETITEM(consts, oparg);
- Py_INCREF(value);
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(STORE_FAST__LOAD_FAST) {
- PyObject *value = POP();
- SETLOCAL(oparg, value);
- NEXTOPARG();
- next_instr++;
- value = GETLOCAL(oparg);
- if (value == NULL) {
- goto unbound_local_error;
- }
- Py_INCREF(value);
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(STORE_FAST__STORE_FAST) {
- PyObject *value = POP();
- SETLOCAL(oparg, value);
- NEXTOPARG();
- next_instr++;
- value = POP();
- SETLOCAL(oparg, value);
- DISPATCH();
- }
-
- TARGET(LOAD_CONST__LOAD_FAST) {
- PyObject *value = GETITEM(consts, oparg);
- NEXTOPARG();
- next_instr++;
- Py_INCREF(value);
- PUSH(value);
- value = GETLOCAL(oparg);
- if (value == NULL) {
- goto unbound_local_error;
- }
- Py_INCREF(value);
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(POP_TOP) {
- PyObject *value = POP();
- Py_DECREF(value);
- DISPATCH();
- }
-
- TARGET(PUSH_NULL) {
- /* Use BASIC_PUSH as NULL is not a valid object pointer */
- BASIC_PUSH(NULL);
- DISPATCH();
- }
-
- TARGET(UNARY_POSITIVE) {
- PyObject *value = TOP();
- PyObject *res = PyNumber_Positive(value);
- Py_DECREF(value);
- SET_TOP(res);
- if (res == NULL)
- goto error;
- DISPATCH();
- }
-
- TARGET(UNARY_NEGATIVE) {
- PyObject *value = TOP();
- PyObject *res = PyNumber_Negative(value);
- Py_DECREF(value);
- SET_TOP(res);
- if (res == NULL)
- goto error;
- DISPATCH();
- }
-
- TARGET(UNARY_NOT) {
- PyObject *value = TOP();
- int err = PyObject_IsTrue(value);
- Py_DECREF(value);
- if (err == 0) {
- Py_INCREF(Py_True);
- SET_TOP(Py_True);
- DISPATCH();
- }
- else if (err > 0) {
- Py_INCREF(Py_False);
- SET_TOP(Py_False);
- DISPATCH();
- }
- STACK_SHRINK(1);
- goto error;
- }
-
- TARGET(UNARY_INVERT) {
- PyObject *value = TOP();
- PyObject *res = PyNumber_Invert(value);
- Py_DECREF(value);
- SET_TOP(res);
- if (res == NULL)
- goto error;
- DISPATCH();
- }
-
- TARGET(BINARY_OP_MULTIPLY_INT) {
- assert(cframe.use_tracing == 0);
- PyObject *left = SECOND();
- PyObject *right = TOP();
- DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
- DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
- STAT_INC(BINARY_OP, hit);
- PyObject *prod = _PyLong_Multiply((PyLongObject *)left, (PyLongObject *)right);
- SET_SECOND(prod);
- _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
- _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
- STACK_SHRINK(1);
- if (prod == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
- DISPATCH();
- }
-
- TARGET(BINARY_OP_MULTIPLY_FLOAT) {
- assert(cframe.use_tracing == 0);
- PyObject *left = SECOND();
- PyObject *right = TOP();
- DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
- DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
- STAT_INC(BINARY_OP, hit);
- double dprod = ((PyFloatObject *)left)->ob_fval *
- ((PyFloatObject *)right)->ob_fval;
- PyObject *prod = PyFloat_FromDouble(dprod);
- SET_SECOND(prod);
- _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
- _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
- STACK_SHRINK(1);
- if (prod == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
- DISPATCH();
- }
-
- TARGET(BINARY_OP_SUBTRACT_INT) {
- assert(cframe.use_tracing == 0);
- PyObject *left = SECOND();
- PyObject *right = TOP();
- DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
- DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
- STAT_INC(BINARY_OP, hit);
- PyObject *sub = _PyLong_Subtract((PyLongObject *)left, (PyLongObject *)right);
- SET_SECOND(sub);
- _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
- _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
- STACK_SHRINK(1);
- if (sub == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
- DISPATCH();
- }
-
- TARGET(BINARY_OP_SUBTRACT_FLOAT) {
- assert(cframe.use_tracing == 0);
- PyObject *left = SECOND();
- PyObject *right = TOP();
- DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
- DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
- STAT_INC(BINARY_OP, hit);
- double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval;
- PyObject *sub = PyFloat_FromDouble(dsub);
- SET_SECOND(sub);
- _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
- _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
- STACK_SHRINK(1);
- if (sub == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
- DISPATCH();
- }
-
- TARGET(BINARY_OP_ADD_UNICODE) {
- assert(cframe.use_tracing == 0);
- PyObject *left = SECOND();
- PyObject *right = TOP();
- DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
- DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
- STAT_INC(BINARY_OP, hit);
- PyObject *res = PyUnicode_Concat(left, right);
- STACK_SHRINK(1);
- SET_TOP(res);
- _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
- _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
- if (TOP() == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
- DISPATCH();
- }
-
- TARGET(BINARY_OP_INPLACE_ADD_UNICODE) {
- assert(cframe.use_tracing == 0);
- PyObject *left = SECOND();
- PyObject *right = TOP();
- DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
- DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
- _Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
- assert(_Py_OPCODE(true_next) == STORE_FAST ||
- _Py_OPCODE(true_next) == STORE_FAST__LOAD_FAST);
- PyObject **target_local = &GETLOCAL(_Py_OPARG(true_next));
- DEOPT_IF(*target_local != left, BINARY_OP);
- STAT_INC(BINARY_OP, hit);
- /* Handle `left = left + right` or `left += right` for str.
- *
- * When possible, extend `left` in place rather than
- * allocating a new PyUnicodeObject. This attempts to avoid
- * quadratic behavior when one neglects to use str.join().
- *
- * If `left` has only two references remaining (one from
- * the stack, one in the locals), DECREFing `left` leaves
- * only the locals reference, so PyUnicode_Append knows
- * that the string is safe to mutate.
- */
- assert(Py_REFCNT(left) >= 2);
- _Py_DECREF_NO_DEALLOC(left);
- STACK_SHRINK(2);
- PyUnicode_Append(target_local, right);
- _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
- if (*target_local == NULL) {
- goto error;
- }
- // The STORE_FAST is already done.
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1);
- DISPATCH();
- }
-
- TARGET(BINARY_OP_ADD_FLOAT) {
- assert(cframe.use_tracing == 0);
- PyObject *left = SECOND();
- PyObject *right = TOP();
- DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
- DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
- STAT_INC(BINARY_OP, hit);
- double dsum = ((PyFloatObject *)left)->ob_fval +
- ((PyFloatObject *)right)->ob_fval;
- PyObject *sum = PyFloat_FromDouble(dsum);
- SET_SECOND(sum);
- _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
- _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
- STACK_SHRINK(1);
- if (sum == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
- DISPATCH();
- }
-
- TARGET(BINARY_OP_ADD_INT) {
- assert(cframe.use_tracing == 0);
- PyObject *left = SECOND();
- PyObject *right = TOP();
- DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
- DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
- STAT_INC(BINARY_OP, hit);
- PyObject *sum = _PyLong_Add((PyLongObject *)left, (PyLongObject *)right);
- SET_SECOND(sum);
- _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
- _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
- STACK_SHRINK(1);
- if (sum == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
- DISPATCH();
- }
-
- TARGET(BINARY_SUBSCR) {
- PREDICTED(BINARY_SUBSCR);
- PyObject *sub = POP();
- PyObject *container = TOP();
- PyObject *res = PyObject_GetItem(container, sub);
- Py_DECREF(container);
- Py_DECREF(sub);
- SET_TOP(res);
- if (res == NULL)
- goto error;
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
- DISPATCH();
- }
-
- TARGET(BINARY_SUBSCR_ADAPTIVE) {
- _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- PyObject *sub = TOP();
- PyObject *container = SECOND();
- next_instr--;
- if (_Py_Specialize_BinarySubscr(container, sub, next_instr) < 0) {
- next_instr++;
- goto error;
- }
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(BINARY_SUBSCR, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(BINARY_SUBSCR);
- }
- }
-
- TARGET(BINARY_SUBSCR_LIST_INT) {
- assert(cframe.use_tracing == 0);
- PyObject *sub = TOP();
- PyObject *list = SECOND();
- DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
- DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR);
-
- // Deopt unless 0 <= sub < PyList_Size(list)
- Py_ssize_t signed_magnitude = Py_SIZE(sub);
- DEOPT_IF(((size_t)signed_magnitude) > 1, BINARY_SUBSCR);
- assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0);
- Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
- DEOPT_IF(index >= PyList_GET_SIZE(list), BINARY_SUBSCR);
- STAT_INC(BINARY_SUBSCR, hit);
- PyObject *res = PyList_GET_ITEM(list, index);
- assert(res != NULL);
- Py_INCREF(res);
- STACK_SHRINK(1);
- _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
- SET_TOP(res);
- Py_DECREF(list);
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
- DISPATCH();
- }
-
- TARGET(BINARY_SUBSCR_TUPLE_INT) {
- assert(cframe.use_tracing == 0);
- PyObject *sub = TOP();
- PyObject *tuple = SECOND();
- DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
- DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR);
-
- // Deopt unless 0 <= sub < PyTuple_Size(list)
- Py_ssize_t signed_magnitude = Py_SIZE(sub);
- DEOPT_IF(((size_t)signed_magnitude) > 1, BINARY_SUBSCR);
- assert(((PyLongObject *)_PyLong_GetZero())->ob_digit[0] == 0);
- Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
- DEOPT_IF(index >= PyTuple_GET_SIZE(tuple), BINARY_SUBSCR);
- STAT_INC(BINARY_SUBSCR, hit);
- PyObject *res = PyTuple_GET_ITEM(tuple, index);
- assert(res != NULL);
- Py_INCREF(res);
- STACK_SHRINK(1);
- _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
- SET_TOP(res);
- Py_DECREF(tuple);
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
- DISPATCH();
- }
-
- TARGET(BINARY_SUBSCR_DICT) {
- assert(cframe.use_tracing == 0);
- PyObject *dict = SECOND();
- DEOPT_IF(!PyDict_CheckExact(SECOND()), BINARY_SUBSCR);
- STAT_INC(BINARY_SUBSCR, hit);
- PyObject *sub = TOP();
- PyObject *res = PyDict_GetItemWithError(dict, sub);
- if (res == NULL) {
- goto binary_subscr_dict_error;
- }
- Py_INCREF(res);
- STACK_SHRINK(1);
- Py_DECREF(sub);
- SET_TOP(res);
- Py_DECREF(dict);
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
- DISPATCH();
- }
-
- TARGET(BINARY_SUBSCR_GETITEM) {
- DEOPT_IF(tstate->interp->eval_frame, BINARY_SUBSCR);
- PyObject *sub = TOP();
- PyObject *container = SECOND();
- _PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
- uint32_t type_version = read_u32(cache->type_version);
- PyTypeObject *tp = Py_TYPE(container);
- DEOPT_IF(tp->tp_version_tag != type_version, BINARY_SUBSCR);
- assert(tp->tp_flags & Py_TPFLAGS_HEAPTYPE);
- PyObject *cached = ((PyHeapTypeObject *)tp)->_spec_cache.getitem;
- assert(PyFunction_Check(cached));
- PyFunctionObject *getitem = (PyFunctionObject *)cached;
- DEOPT_IF(getitem->func_version != cache->func_version, BINARY_SUBSCR);
- PyCodeObject *code = (PyCodeObject *)getitem->func_code;
- size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
- assert(code->co_argcount == 2);
- _PyInterpreterFrame *new_frame = _PyThreadState_BumpFramePointer(tstate, size);
- if (new_frame == NULL) {
- goto error;
- }
- CALL_STAT_INC(frames_pushed);
- Py_INCREF(getitem);
- _PyFrame_InitializeSpecials(new_frame, getitem,
- NULL, code->co_nlocalsplus);
- STACK_SHRINK(2);
- new_frame->localsplus[0] = container;
- new_frame->localsplus[1] = sub;
- for (int i = 2; i < code->co_nlocalsplus; i++) {
- new_frame->localsplus[i] = NULL;
- }
- _PyFrame_SetStackPointer(frame, stack_pointer);
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
- frame->prev_instr = next_instr - 1;
- new_frame->previous = frame;
- frame = cframe.current_frame = new_frame;
- CALL_STAT_INC(inlined_py_calls);
- goto start_frame;
- }
-
- TARGET(LIST_APPEND) {
- PyObject *v = POP();
- PyObject *list = PEEK(oparg);
- if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0)
- goto error;
- PREDICT(JUMP_BACKWARD_QUICK);
- DISPATCH();
- }
-
- TARGET(SET_ADD) {
- PyObject *v = POP();
- PyObject *set = PEEK(oparg);
- int err;
- err = PySet_Add(set, v);
- Py_DECREF(v);
- if (err != 0)
- goto error;
- PREDICT(JUMP_BACKWARD_QUICK);
- DISPATCH();
- }
-
- TARGET(STORE_SUBSCR) {
- PREDICTED(STORE_SUBSCR);
- PyObject *sub = TOP();
- PyObject *container = SECOND();
- PyObject *v = THIRD();
- int err;
- STACK_SHRINK(3);
- /* container[sub] = v */
- err = PyObject_SetItem(container, sub, v);
- Py_DECREF(v);
- Py_DECREF(container);
- Py_DECREF(sub);
- if (err != 0) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
- DISPATCH();
- }
-
- TARGET(STORE_SUBSCR_ADAPTIVE) {
- _PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- PyObject *sub = TOP();
- PyObject *container = SECOND();
- next_instr--;
- if (_Py_Specialize_StoreSubscr(container, sub, next_instr) < 0) {
- next_instr++;
- goto error;
- }
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(STORE_SUBSCR, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(STORE_SUBSCR);
- }
- }
-
- TARGET(STORE_SUBSCR_LIST_INT) {
- assert(cframe.use_tracing == 0);
- PyObject *sub = TOP();
- PyObject *list = SECOND();
- PyObject *value = THIRD();
- DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR);
- DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR);
-
- // Ensure nonnegative, zero-or-one-digit ints.
- DEOPT_IF(((size_t)Py_SIZE(sub)) > 1, STORE_SUBSCR);
- Py_ssize_t index = ((PyLongObject*)sub)->ob_digit[0];
- // Ensure index < len(list)
- DEOPT_IF(index >= PyList_GET_SIZE(list), STORE_SUBSCR);
- STAT_INC(STORE_SUBSCR, hit);
-
- PyObject *old_value = PyList_GET_ITEM(list, index);
- PyList_SET_ITEM(list, index, value);
- STACK_SHRINK(3);
- assert(old_value != NULL);
- Py_DECREF(old_value);
- _Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
- Py_DECREF(list);
- JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
- DISPATCH();
- }
-
- TARGET(STORE_SUBSCR_DICT) {
- assert(cframe.use_tracing == 0);
- PyObject *sub = TOP();
- PyObject *dict = SECOND();
- PyObject *value = THIRD();
- DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR);
- STACK_SHRINK(3);
- STAT_INC(STORE_SUBSCR, hit);
- int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value);
- Py_DECREF(dict);
- if (err != 0) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_STORE_SUBSCR);
- DISPATCH();
- }
-
- TARGET(DELETE_SUBSCR) {
- PyObject *sub = TOP();
- PyObject *container = SECOND();
- int err;
- STACK_SHRINK(2);
- /* del container[sub] */
- err = PyObject_DelItem(container, sub);
- Py_DECREF(container);
- Py_DECREF(sub);
- if (err != 0)
- goto error;
- DISPATCH();
- }
-
- TARGET(PRINT_EXPR) {
- PyObject *value = POP();
- PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(displayhook));
- PyObject *res;
- if (hook == NULL) {
- _PyErr_SetString(tstate, PyExc_RuntimeError,
- "lost sys.displayhook");
- Py_DECREF(value);
- goto error;
- }
- res = PyObject_CallOneArg(hook, value);
- Py_DECREF(value);
- if (res == NULL)
- goto error;
- Py_DECREF(res);
- DISPATCH();
- }
-
- TARGET(RAISE_VARARGS) {
- PyObject *cause = NULL, *exc = NULL;
- switch (oparg) {
- case 2:
- cause = POP(); /* cause */
- /* fall through */
- case 1:
- exc = POP(); /* exc */
- /* fall through */
- case 0:
- if (do_raise(tstate, exc, cause)) {
- goto exception_unwind;
- }
- break;
- default:
- _PyErr_SetString(tstate, PyExc_SystemError,
- "bad RAISE_VARARGS oparg");
- break;
- }
- goto error;
- }
-
- TARGET(RETURN_VALUE) {
- PyObject *retval = POP();
- assert(EMPTY());
- _PyFrame_SetStackPointer(frame, stack_pointer);
- TRACE_FUNCTION_EXIT();
- DTRACE_FUNCTION_EXIT();
- _Py_LeaveRecursiveCallTstate(tstate);
- if (!frame->is_entry) {
- // GH-99729: We need to unlink the frame *before* clearing it:
- _PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
- _PyEvalFrameClearAndPop(tstate, dying);
- _PyFrame_StackPush(frame, retval);
- goto resume_frame;
- }
- /* Restore previous cframe and return. */
- tstate->cframe = cframe.previous;
- tstate->cframe->use_tracing = cframe.use_tracing;
- assert(tstate->cframe->current_frame == frame->previous);
- assert(!_PyErr_Occurred(tstate));
- return retval;
- }
-
- TARGET(GET_AITER) {
- unaryfunc getter = NULL;
- PyObject *iter = NULL;
- PyObject *obj = TOP();
- PyTypeObject *type = Py_TYPE(obj);
-
- if (type->tp_as_async != NULL) {
- getter = type->tp_as_async->am_aiter;
- }
-
- if (getter != NULL) {
- iter = (*getter)(obj);
- Py_DECREF(obj);
- if (iter == NULL) {
- SET_TOP(NULL);
- goto error;
- }
- }
- else {
- SET_TOP(NULL);
- _PyErr_Format(tstate, PyExc_TypeError,
- "'async for' requires an object with "
- "__aiter__ method, got %.100s",
- type->tp_name);
- Py_DECREF(obj);
- goto error;
- }
-
- if (Py_TYPE(iter)->tp_as_async == NULL ||
- Py_TYPE(iter)->tp_as_async->am_anext == NULL) {
-
- SET_TOP(NULL);
- _PyErr_Format(tstate, PyExc_TypeError,
- "'async for' received an object from __aiter__ "
- "that does not implement __anext__: %.100s",
- Py_TYPE(iter)->tp_name);
- Py_DECREF(iter);
- goto error;
- }
-
- SET_TOP(iter);
- DISPATCH();
- }
-
- TARGET(GET_ANEXT) {
- unaryfunc getter = NULL;
- PyObject *next_iter = NULL;
- PyObject *awaitable = NULL;
- PyObject *aiter = TOP();
- PyTypeObject *type = Py_TYPE(aiter);
-
- if (PyAsyncGen_CheckExact(aiter)) {
- awaitable = type->tp_as_async->am_anext(aiter);
- if (awaitable == NULL) {
- goto error;
- }
- } else {
- if (type->tp_as_async != NULL){
- getter = type->tp_as_async->am_anext;
- }
-
- if (getter != NULL) {
- next_iter = (*getter)(aiter);
- if (next_iter == NULL) {
- goto error;
- }
- }
- else {
- _PyErr_Format(tstate, PyExc_TypeError,
- "'async for' requires an iterator with "
- "__anext__ method, got %.100s",
- type->tp_name);
- goto error;
- }
-
- awaitable = _PyCoro_GetAwaitableIter(next_iter);
- if (awaitable == NULL) {
- _PyErr_FormatFromCause(
- PyExc_TypeError,
- "'async for' received an invalid object "
- "from __anext__: %.100s",
- Py_TYPE(next_iter)->tp_name);
-
- Py_DECREF(next_iter);
- goto error;
- } else {
- Py_DECREF(next_iter);
- }
- }
-
- PUSH(awaitable);
- PREDICT(LOAD_CONST);
- DISPATCH();
- }
-
- TARGET(GET_AWAITABLE) {
- PREDICTED(GET_AWAITABLE);
- PyObject *iterable = TOP();
- PyObject *iter = _PyCoro_GetAwaitableIter(iterable);
-
- if (iter == NULL) {
- format_awaitable_error(tstate, Py_TYPE(iterable), oparg);
- }
-
- Py_DECREF(iterable);
-
- if (iter != NULL && PyCoro_CheckExact(iter)) {
- PyObject *yf = _PyGen_yf((PyGenObject*)iter);
- if (yf != NULL) {
- /* `iter` is a coroutine object that is being
- awaited, `yf` is a pointer to the current awaitable
- being awaited on. */
- Py_DECREF(yf);
- Py_CLEAR(iter);
- _PyErr_SetString(tstate, PyExc_RuntimeError,
- "coroutine is being awaited already");
- /* The code below jumps to `error` if `iter` is NULL. */
- }
- }
-
- SET_TOP(iter); /* Even if it's NULL */
-
- if (iter == NULL) {
- goto error;
- }
-
- PREDICT(LOAD_CONST);
- DISPATCH();
- }
-
- TARGET(SEND) {
- assert(frame->is_entry);
- assert(STACK_LEVEL() >= 2);
- PyObject *v = POP();
- PyObject *receiver = TOP();
- PySendResult gen_status;
- PyObject *retval;
- if (tstate->c_tracefunc == NULL) {
- gen_status = PyIter_Send(receiver, v, &retval);
- } else {
- if (Py_IsNone(v) && PyIter_Check(receiver)) {
- retval = Py_TYPE(receiver)->tp_iternext(receiver);
- }
- else {
- retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v);
- }
- if (retval == NULL) {
- if (tstate->c_tracefunc != NULL
- && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration))
- call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
- if (_PyGen_FetchStopIterationValue(&retval) == 0) {
- gen_status = PYGEN_RETURN;
- }
- else {
- gen_status = PYGEN_ERROR;
- }
- }
- else {
- gen_status = PYGEN_NEXT;
- }
- }
- Py_DECREF(v);
- if (gen_status == PYGEN_ERROR) {
- assert(retval == NULL);
- goto error;
- }
- if (gen_status == PYGEN_RETURN) {
- assert(retval != NULL);
- Py_DECREF(receiver);
- SET_TOP(retval);
- JUMPBY(oparg);
- DISPATCH();
- }
- assert(gen_status == PYGEN_NEXT);
- assert(retval != NULL);
- PUSH(retval);
- DISPATCH();
- }
-
- TARGET(ASYNC_GEN_WRAP) {
- PyObject *v = TOP();
- assert(frame->f_code->co_flags & CO_ASYNC_GENERATOR);
- PyObject *w = _PyAsyncGenValueWrapperNew(v);
- if (w == NULL) {
- goto error;
- }
- SET_TOP(w);
- Py_DECREF(v);
- DISPATCH();
- }
-
- TARGET(YIELD_VALUE) {
- assert(frame->is_entry);
- PyObject *retval = POP();
- _PyFrame_GetGenerator(frame)->gi_frame_state = FRAME_SUSPENDED;
- _PyFrame_SetStackPointer(frame, stack_pointer);
- TRACE_FUNCTION_EXIT();
- DTRACE_FUNCTION_EXIT();
- _Py_LeaveRecursiveCallTstate(tstate);
- /* Restore previous cframe and return. */
- tstate->cframe = cframe.previous;
- tstate->cframe->use_tracing = cframe.use_tracing;
- assert(tstate->cframe->current_frame == frame->previous);
- assert(!_PyErr_Occurred(tstate));
- return retval;
- }
-
- TARGET(POP_EXCEPT) {
- _PyErr_StackItem *exc_info = tstate->exc_info;
- PyObject *value = exc_info->exc_value;
- exc_info->exc_value = POP();
- Py_XDECREF(value);
- DISPATCH();
- }
-
- TARGET(RERAISE) {
- if (oparg) {
- PyObject *lasti = PEEK(oparg + 1);
- if (PyLong_Check(lasti)) {
- frame->prev_instr = first_instr + PyLong_AsLong(lasti);
- assert(!_PyErr_Occurred(tstate));
- }
- else {
- assert(PyLong_Check(lasti));
- _PyErr_SetString(tstate, PyExc_SystemError, "lasti is not an int");
- goto error;
- }
- }
- PyObject *val = POP();
- assert(val && PyExceptionInstance_Check(val));
- PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val));
- PyObject *tb = PyException_GetTraceback(val);
- _PyErr_Restore(tstate, exc, val, tb);
- goto exception_unwind;
- }
-
- TARGET(PREP_RERAISE_STAR) {
- PyObject *excs = POP();
- assert(PyList_Check(excs));
- PyObject *orig = POP();
-
- PyObject *val = _PyExc_PrepReraiseStar(orig, excs);
- Py_DECREF(excs);
- Py_DECREF(orig);
-
- if (val == NULL) {
- goto error;
- }
-
- PUSH(val);
- DISPATCH();
- }
-
- TARGET(END_ASYNC_FOR) {
- PyObject *val = POP();
- assert(val && PyExceptionInstance_Check(val));
- if (PyErr_GivenExceptionMatches(val, PyExc_StopAsyncIteration)) {
- Py_DECREF(val);
- Py_DECREF(POP());
- DISPATCH();
- }
- else {
- PyObject *exc = Py_NewRef(PyExceptionInstance_Class(val));
- PyObject *tb = PyException_GetTraceback(val);
- _PyErr_Restore(tstate, exc, val, tb);
- goto exception_unwind;
- }
- }
-
- TARGET(LOAD_ASSERTION_ERROR) {
- PyObject *value = PyExc_AssertionError;
- Py_INCREF(value);
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(LOAD_BUILD_CLASS) {
- PyObject *bc;
- if (PyDict_CheckExact(BUILTINS())) {
- bc = _PyDict_GetItemWithError(BUILTINS(),
- &_Py_ID(__build_class__));
- if (bc == NULL) {
- if (!_PyErr_Occurred(tstate)) {
- _PyErr_SetString(tstate, PyExc_NameError,
- "__build_class__ not found");
- }
- goto error;
- }
- Py_INCREF(bc);
- }
- else {
- bc = PyObject_GetItem(BUILTINS(), &_Py_ID(__build_class__));
- if (bc == NULL) {
- if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError))
- _PyErr_SetString(tstate, PyExc_NameError,
- "__build_class__ not found");
- goto error;
- }
- }
- PUSH(bc);
- DISPATCH();
- }
-
- TARGET(STORE_NAME) {
- PyObject *name = GETITEM(names, oparg);
- PyObject *v = POP();
- PyObject *ns = LOCALS();
- int err;
- if (ns == NULL) {
- _PyErr_Format(tstate, PyExc_SystemError,
- "no locals found when storing %R", name);
- Py_DECREF(v);
- goto error;
- }
- if (PyDict_CheckExact(ns))
- err = PyDict_SetItem(ns, name, v);
- else
- err = PyObject_SetItem(ns, name, v);
- Py_DECREF(v);
- if (err != 0)
- goto error;
- DISPATCH();
- }
-
- TARGET(DELETE_NAME) {
- PyObject *name = GETITEM(names, oparg);
- PyObject *ns = LOCALS();
- int err;
- if (ns == NULL) {
- _PyErr_Format(tstate, PyExc_SystemError,
- "no locals when deleting %R", name);
- goto error;
- }
- err = PyObject_DelItem(ns, name);
- if (err != 0) {
- format_exc_check_arg(tstate, PyExc_NameError,
- NAME_ERROR_MSG,
- name);
- goto error;
- }
- DISPATCH();
- }
-
- TARGET(UNPACK_SEQUENCE) {
- PREDICTED(UNPACK_SEQUENCE);
- PyObject *seq = POP();
- PyObject **top = stack_pointer + oparg;
- if (!unpack_iterable(tstate, seq, oparg, -1, top)) {
- Py_DECREF(seq);
- goto error;
- }
- STACK_GROW(oparg);
- Py_DECREF(seq);
- JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE);
- DISPATCH();
- }
-
- TARGET(UNPACK_SEQUENCE_ADAPTIVE) {
- assert(cframe.use_tracing == 0);
- _PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- PyObject *seq = TOP();
- next_instr--;
- _Py_Specialize_UnpackSequence(seq, next_instr, oparg);
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(UNPACK_SEQUENCE, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(UNPACK_SEQUENCE);
- }
- }
-
- TARGET(UNPACK_SEQUENCE_TWO_TUPLE) {
- PyObject *seq = TOP();
- DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE);
- DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE);
- STAT_INC(UNPACK_SEQUENCE, hit);
- SET_TOP(Py_NewRef(PyTuple_GET_ITEM(seq, 1)));
- PUSH(Py_NewRef(PyTuple_GET_ITEM(seq, 0)));
- Py_DECREF(seq);
- JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE);
- DISPATCH();
- }
-
- TARGET(UNPACK_SEQUENCE_TUPLE) {
- PyObject *seq = TOP();
- DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE);
- DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE);
- STAT_INC(UNPACK_SEQUENCE, hit);
- STACK_SHRINK(1);
- PyObject **items = _PyTuple_ITEMS(seq);
- while (oparg--) {
- PUSH(Py_NewRef(items[oparg]));
- }
- Py_DECREF(seq);
- JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE);
- DISPATCH();
- }
-
- TARGET(UNPACK_SEQUENCE_LIST) {
- PyObject *seq = TOP();
- DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE);
- DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE);
- STAT_INC(UNPACK_SEQUENCE, hit);
- STACK_SHRINK(1);
- PyObject **items = _PyList_ITEMS(seq);
- while (oparg--) {
- PUSH(Py_NewRef(items[oparg]));
- }
- Py_DECREF(seq);
- JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE);
- DISPATCH();
- }
-
- TARGET(UNPACK_EX) {
- int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
- PyObject *seq = POP();
- PyObject **top = stack_pointer + totalargs;
- if (!unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top)) {
- Py_DECREF(seq);
- goto error;
- }
- STACK_GROW(totalargs);
- Py_DECREF(seq);
- DISPATCH();
- }
-
- TARGET(STORE_ATTR) {
- PREDICTED(STORE_ATTR);
- PyObject *name = GETITEM(names, oparg);
- PyObject *owner = TOP();
- PyObject *v = SECOND();
- int err;
- STACK_SHRINK(2);
- err = PyObject_SetAttr(owner, name, v);
- Py_DECREF(v);
- Py_DECREF(owner);
- if (err != 0) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_STORE_ATTR);
- DISPATCH();
- }
-
- TARGET(DELETE_ATTR) {
- PyObject *name = GETITEM(names, oparg);
- PyObject *owner = POP();
- int err;
- err = PyObject_SetAttr(owner, name, (PyObject *)NULL);
- Py_DECREF(owner);
- if (err != 0)
- goto error;
- DISPATCH();
- }
-
- TARGET(STORE_GLOBAL) {
- PyObject *name = GETITEM(names, oparg);
- PyObject *v = POP();
- int err;
- err = PyDict_SetItem(GLOBALS(), name, v);
- Py_DECREF(v);
- if (err != 0)
- goto error;
- DISPATCH();
- }
-
- TARGET(DELETE_GLOBAL) {
- PyObject *name = GETITEM(names, oparg);
- int err;
- err = PyDict_DelItem(GLOBALS(), name);
- if (err != 0) {
- if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
- format_exc_check_arg(tstate, PyExc_NameError,
- NAME_ERROR_MSG, name);
- }
- goto error;
- }
- DISPATCH();
- }
-
- TARGET(LOAD_NAME) {
- PyObject *name = GETITEM(names, oparg);
- PyObject *locals = LOCALS();
- PyObject *v;
- if (locals == NULL) {
- _PyErr_Format(tstate, PyExc_SystemError,
- "no locals when loading %R", name);
- goto error;
- }
- if (PyDict_CheckExact(locals)) {
- v = PyDict_GetItemWithError(locals, name);
- if (v != NULL) {
- Py_INCREF(v);
- }
- else if (_PyErr_Occurred(tstate)) {
- goto error;
- }
- }
- else {
- v = PyObject_GetItem(locals, name);
- if (v == NULL) {
- if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError))
- goto error;
- _PyErr_Clear(tstate);
- }
- }
- if (v == NULL) {
- v = PyDict_GetItemWithError(GLOBALS(), name);
- if (v != NULL) {
- Py_INCREF(v);
- }
- else if (_PyErr_Occurred(tstate)) {
- goto error;
- }
- else {
- if (PyDict_CheckExact(BUILTINS())) {
- v = PyDict_GetItemWithError(BUILTINS(), name);
- if (v == NULL) {
- if (!_PyErr_Occurred(tstate)) {
- format_exc_check_arg(
- tstate, PyExc_NameError,
- NAME_ERROR_MSG, name);
- }
- goto error;
- }
- Py_INCREF(v);
- }
- else {
- v = PyObject_GetItem(BUILTINS(), name);
- if (v == NULL) {
- if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
- format_exc_check_arg(
- tstate, PyExc_NameError,
- NAME_ERROR_MSG, name);
- }
- goto error;
- }
- }
- }
- }
- PUSH(v);
- DISPATCH();
- }
-
- TARGET(LOAD_GLOBAL) {
- PREDICTED(LOAD_GLOBAL);
- int push_null = oparg & 1;
- PEEK(0) = NULL;
- PyObject *name = GETITEM(names, oparg>>1);
- PyObject *v;
- if (PyDict_CheckExact(GLOBALS())
- && PyDict_CheckExact(BUILTINS()))
- {
- v = _PyDict_LoadGlobal((PyDictObject *)GLOBALS(),
- (PyDictObject *)BUILTINS(),
- name);
- if (v == NULL) {
- if (!_PyErr_Occurred(tstate)) {
- /* _PyDict_LoadGlobal() returns NULL without raising
- * an exception if the key doesn't exist */
- format_exc_check_arg(tstate, PyExc_NameError,
- NAME_ERROR_MSG, name);
- }
- goto error;
- }
- Py_INCREF(v);
- }
- else {
- /* Slow-path if globals or builtins is not a dict */
-
- /* namespace 1: globals */
- v = PyObject_GetItem(GLOBALS(), name);
- if (v == NULL) {
- if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
- goto error;
- }
- _PyErr_Clear(tstate);
-
- /* namespace 2: builtins */
- v = PyObject_GetItem(BUILTINS(), name);
- if (v == NULL) {
- if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
- format_exc_check_arg(
- tstate, PyExc_NameError,
- NAME_ERROR_MSG, name);
- }
- goto error;
- }
- }
- }
- /* Skip over inline cache */
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL);
- STACK_GROW(push_null);
- PUSH(v);
- DISPATCH();
- }
-
- TARGET(LOAD_GLOBAL_ADAPTIVE) {
- assert(cframe.use_tracing == 0);
- _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- PyObject *name = GETITEM(names, oparg>>1);
- next_instr--;
- if (_Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name) < 0) {
- next_instr++;
- goto error;
- }
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(LOAD_GLOBAL, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(LOAD_GLOBAL);
- }
- }
-
- TARGET(LOAD_GLOBAL_MODULE) {
- assert(cframe.use_tracing == 0);
- DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL);
- PyDictObject *dict = (PyDictObject *)GLOBALS();
- _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
- uint32_t version = read_u32(cache->module_keys_version);
- DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL);
- assert(DK_IS_UNICODE(dict->ma_keys));
- PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(dict->ma_keys);
- PyObject *res = entries[cache->index].me_value;
- DEOPT_IF(res == NULL, LOAD_GLOBAL);
- int push_null = oparg & 1;
- PEEK(0) = NULL;
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL);
- STAT_INC(LOAD_GLOBAL, hit);
- STACK_GROW(push_null+1);
- Py_INCREF(res);
- SET_TOP(res);
- DISPATCH();
- }
-
- TARGET(LOAD_GLOBAL_BUILTIN) {
- assert(cframe.use_tracing == 0);
- DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL);
- DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL);
- PyDictObject *mdict = (PyDictObject *)GLOBALS();
- PyDictObject *bdict = (PyDictObject *)BUILTINS();
- _PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
- uint32_t mod_version = read_u32(cache->module_keys_version);
- uint16_t bltn_version = cache->builtin_keys_version;
- DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL);
- DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL);
- assert(DK_IS_UNICODE(bdict->ma_keys));
- PyDictUnicodeEntry *entries = DK_UNICODE_ENTRIES(bdict->ma_keys);
- PyObject *res = entries[cache->index].me_value;
- DEOPT_IF(res == NULL, LOAD_GLOBAL);
- int push_null = oparg & 1;
- PEEK(0) = NULL;
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_GLOBAL);
- STAT_INC(LOAD_GLOBAL, hit);
- STACK_GROW(push_null+1);
- Py_INCREF(res);
- SET_TOP(res);
- DISPATCH();
- }
-
- TARGET(DELETE_FAST) {
- PyObject *v = GETLOCAL(oparg);
- if (v != NULL) {
- SETLOCAL(oparg, NULL);
- DISPATCH();
- }
- goto unbound_local_error;
- }
-
- TARGET(MAKE_CELL) {
- // "initial" is probably NULL but not if it's an arg (or set
- // via PyFrame_LocalsToFast() before MAKE_CELL has run).
- PyObject *initial = GETLOCAL(oparg);
- PyObject *cell = PyCell_New(initial);
- if (cell == NULL) {
- goto resume_with_error;
- }
- SETLOCAL(oparg, cell);
- DISPATCH();
- }
-
- TARGET(DELETE_DEREF) {
- PyObject *cell = GETLOCAL(oparg);
- PyObject *oldobj = PyCell_GET(cell);
- if (oldobj != NULL) {
- PyCell_SET(cell, NULL);
- Py_DECREF(oldobj);
- DISPATCH();
- }
- format_exc_unbound(tstate, frame->f_code, oparg);
- goto error;
- }
-
- TARGET(LOAD_CLASSDEREF) {
- PyObject *name, *value, *locals = LOCALS();
- assert(locals);
- assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus);
- name = PyTuple_GET_ITEM(frame->f_code->co_localsplusnames, oparg);
- if (PyDict_CheckExact(locals)) {
- value = PyDict_GetItemWithError(locals, name);
- if (value != NULL) {
- Py_INCREF(value);
- }
- else if (_PyErr_Occurred(tstate)) {
- goto error;
- }
- }
- else {
- value = PyObject_GetItem(locals, name);
- if (value == NULL) {
- if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
- goto error;
- }
- _PyErr_Clear(tstate);
- }
- }
- if (!value) {
- PyObject *cell = GETLOCAL(oparg);
- value = PyCell_GET(cell);
- if (value == NULL) {
- format_exc_unbound(tstate, frame->f_code, oparg);
- goto error;
- }
- Py_INCREF(value);
- }
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(LOAD_DEREF) {
- PyObject *cell = GETLOCAL(oparg);
- PyObject *value = PyCell_GET(cell);
- if (value == NULL) {
- format_exc_unbound(tstate, frame->f_code, oparg);
- goto error;
- }
- Py_INCREF(value);
- PUSH(value);
- DISPATCH();
- }
-
- TARGET(STORE_DEREF) {
- PyObject *v = POP();
- PyObject *cell = GETLOCAL(oparg);
- PyObject *oldobj = PyCell_GET(cell);
- PyCell_SET(cell, v);
- Py_XDECREF(oldobj);
- DISPATCH();
- }
-
- TARGET(COPY_FREE_VARS) {
- /* Copy closure variables to free variables */
- PyCodeObject *co = frame->f_code;
- PyObject *closure = frame->f_func->func_closure;
- int offset = co->co_nlocals + co->co_nplaincellvars;
- assert(oparg == co->co_nfreevars);
- for (int i = 0; i < oparg; ++i) {
- PyObject *o = PyTuple_GET_ITEM(closure, i);
- Py_INCREF(o);
- frame->localsplus[offset + i] = o;
- }
- DISPATCH();
- }
-
- TARGET(BUILD_STRING) {
- PyObject *str;
- str = _PyUnicode_JoinArray(&_Py_STR(empty),
- stack_pointer - oparg, oparg);
- if (str == NULL)
- goto error;
- while (--oparg >= 0) {
- PyObject *item = POP();
- Py_DECREF(item);
- }
- PUSH(str);
- DISPATCH();
- }
-
- TARGET(BUILD_TUPLE) {
- PyObject *tup = PyTuple_New(oparg);
- if (tup == NULL)
- goto error;
- while (--oparg >= 0) {
- PyObject *item = POP();
- PyTuple_SET_ITEM(tup, oparg, item);
- }
- PUSH(tup);
- DISPATCH();
- }
-
- TARGET(BUILD_LIST) {
- PyObject *list = PyList_New(oparg);
- if (list == NULL)
- goto error;
- while (--oparg >= 0) {
- PyObject *item = POP();
- PyList_SET_ITEM(list, oparg, item);
- }
- PUSH(list);
- DISPATCH();
- }
-
- TARGET(LIST_TO_TUPLE) {
- PyObject *list = POP();
- PyObject *tuple = PyList_AsTuple(list);
- Py_DECREF(list);
- if (tuple == NULL) {
- goto error;
- }
- PUSH(tuple);
- DISPATCH();
- }
-
- TARGET(LIST_EXTEND) {
- PyObject *iterable = POP();
- PyObject *list = PEEK(oparg);
- PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable);
- if (none_val == NULL) {
- if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) &&
- (Py_TYPE(iterable)->tp_iter == NULL && !PySequence_Check(iterable)))
- {
- _PyErr_Clear(tstate);
- _PyErr_Format(tstate, PyExc_TypeError,
- "Value after * must be an iterable, not %.200s",
- Py_TYPE(iterable)->tp_name);
- }
- Py_DECREF(iterable);
- goto error;
- }
- Py_DECREF(none_val);
- Py_DECREF(iterable);
- DISPATCH();
- }
-
- TARGET(SET_UPDATE) {
- PyObject *iterable = POP();
- PyObject *set = PEEK(oparg);
- int err = _PySet_Update(set, iterable);
- Py_DECREF(iterable);
- if (err < 0) {
- goto error;
- }
- DISPATCH();
- }
-
- TARGET(BUILD_SET) {
- PyObject *set = PySet_New(NULL);
- int err = 0;
- int i;
- if (set == NULL)
- goto error;
- for (i = oparg; i > 0; i--) {
- PyObject *item = PEEK(i);
- if (err == 0)
- err = PySet_Add(set, item);
- Py_DECREF(item);
- }
- STACK_SHRINK(oparg);
- if (err != 0) {
- Py_DECREF(set);
- goto error;
- }
- PUSH(set);
- DISPATCH();
- }
-
- TARGET(BUILD_MAP) {
- PyObject *map = _PyDict_FromItems(
- &PEEK(2*oparg), 2,
- &PEEK(2*oparg - 1), 2,
- oparg);
-
- while (oparg--) {
- Py_DECREF(POP());
- Py_DECREF(POP());
- }
- if (map == NULL) {
- goto error;
- }
- PUSH(map);
- DISPATCH();
- }
-
- TARGET(SETUP_ANNOTATIONS) {
- int err;
- PyObject *ann_dict;
- if (LOCALS() == NULL) {
- _PyErr_Format(tstate, PyExc_SystemError,
- "no locals found when setting up annotations");
- goto error;
- }
- /* check if __annotations__ in locals()... */
- if (PyDict_CheckExact(LOCALS())) {
- ann_dict = _PyDict_GetItemWithError(LOCALS(),
- &_Py_ID(__annotations__));
- if (ann_dict == NULL) {
- if (_PyErr_Occurred(tstate)) {
- goto error;
- }
- /* ...if not, create a new one */
- ann_dict = PyDict_New();
- if (ann_dict == NULL) {
- goto error;
- }
- err = PyDict_SetItem(LOCALS(), &_Py_ID(__annotations__),
- ann_dict);
- Py_DECREF(ann_dict);
- if (err != 0) {
- goto error;
- }
- }
- }
- else {
- /* do the same if locals() is not a dict */
- ann_dict = PyObject_GetItem(LOCALS(), &_Py_ID(__annotations__));
- if (ann_dict == NULL) {
- if (!_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
- goto error;
- }
- _PyErr_Clear(tstate);
- ann_dict = PyDict_New();
- if (ann_dict == NULL) {
- goto error;
- }
- err = PyObject_SetItem(LOCALS(), &_Py_ID(__annotations__),
- ann_dict);
- Py_DECREF(ann_dict);
- if (err != 0) {
- goto error;
- }
- }
- else {
- Py_DECREF(ann_dict);
- }
- }
- DISPATCH();
- }
-
- TARGET(BUILD_CONST_KEY_MAP) {
- PyObject *map;
- PyObject *keys = TOP();
- if (!PyTuple_CheckExact(keys) ||
- PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) {
- _PyErr_SetString(tstate, PyExc_SystemError,
- "bad BUILD_CONST_KEY_MAP keys argument");
- goto error;
- }
- map = _PyDict_FromItems(
- &PyTuple_GET_ITEM(keys, 0), 1,
- &PEEK(oparg + 1), 1, oparg);
- if (map == NULL) {
- goto error;
- }
-
- Py_DECREF(POP());
- while (oparg--) {
- Py_DECREF(POP());
- }
- PUSH(map);
- DISPATCH();
- }
-
- TARGET(DICT_UPDATE) {
- PyObject *update = POP();
- PyObject *dict = PEEK(oparg);
- if (PyDict_Update(dict, update) < 0) {
- if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
- _PyErr_Format(tstate, PyExc_TypeError,
- "'%.200s' object is not a mapping",
- Py_TYPE(update)->tp_name);
- }
- Py_DECREF(update);
- goto error;
- }
- Py_DECREF(update);
- DISPATCH();
- }
-
- TARGET(DICT_MERGE) {
- PyObject *update = POP();
- PyObject *dict = PEEK(oparg);
-
- if (_PyDict_MergeEx(dict, update, 2) < 0) {
- format_kwargs_error(tstate, PEEK(2 + oparg), update);
- Py_DECREF(update);
- goto error;
- }
- Py_DECREF(update);
- PREDICT(CALL_FUNCTION_EX);
- DISPATCH();
- }
-
- TARGET(MAP_ADD) {
- PyObject *value = TOP();
- PyObject *key = SECOND();
- PyObject *map;
- STACK_SHRINK(2);
- map = PEEK(oparg); /* dict */
- assert(PyDict_CheckExact(map));
- /* map[key] = value */
- if (_PyDict_SetItem_Take2((PyDictObject *)map, key, value) != 0) {
- goto error;
- }
- PREDICT(JUMP_BACKWARD_QUICK);
- DISPATCH();
- }
-
- TARGET(LOAD_ATTR) {
- PREDICTED(LOAD_ATTR);
- PyObject *name = GETITEM(names, oparg);
- PyObject *owner = TOP();
- PyObject *res = PyObject_GetAttr(owner, name);
- if (res == NULL) {
- goto error;
- }
- Py_DECREF(owner);
- SET_TOP(res);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
- DISPATCH();
- }
-
- TARGET(LOAD_ATTR_ADAPTIVE) {
- assert(cframe.use_tracing == 0);
- _PyAttrCache *cache = (_PyAttrCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- PyObject *owner = TOP();
- PyObject *name = GETITEM(names, oparg);
- next_instr--;
- if (_Py_Specialize_LoadAttr(owner, next_instr, name) < 0) {
- next_instr++;
- goto error;
- }
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(LOAD_ATTR, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(LOAD_ATTR);
- }
- }
-
- TARGET(LOAD_ATTR_INSTANCE_VALUE) {
- assert(cframe.use_tracing == 0);
- PyObject *owner = TOP();
- PyObject *res;
- PyTypeObject *tp = Py_TYPE(owner);
- _PyAttrCache *cache = (_PyAttrCache *)next_instr;
- uint32_t type_version = read_u32(cache->version);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
- assert(tp->tp_dictoffset < 0);
- assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictValues *values = *_PyObject_ValuesPointer(owner);
- DEOPT_IF(values == NULL, LOAD_ATTR);
- res = values->values[cache->index];
- DEOPT_IF(res == NULL, LOAD_ATTR);
- STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- SET_TOP(res);
- Py_DECREF(owner);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
- DISPATCH();
- }
-
- TARGET(LOAD_ATTR_MODULE) {
- assert(cframe.use_tracing == 0);
- // shared with LOAD_METHOD_MODULE
- PyObject *owner = TOP();
- PyObject *res;
- LOAD_MODULE_ATTR_OR_METHOD(ATTR);
- SET_TOP(res);
- Py_DECREF(owner);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
- DISPATCH();
- }
-
- TARGET(LOAD_ATTR_WITH_HINT) {
- assert(cframe.use_tracing == 0);
- PyObject *owner = TOP();
- PyObject *res;
- PyTypeObject *tp = Py_TYPE(owner);
- _PyAttrCache *cache = (_PyAttrCache *)next_instr;
- uint32_t type_version = read_u32(cache->version);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
- assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictObject *dict = *(PyDictObject **)_PyObject_ManagedDictPointer(owner);
- DEOPT_IF(dict == NULL, LOAD_ATTR);
- assert(PyDict_CheckExact((PyObject *)dict));
- PyObject *name = GETITEM(names, oparg);
- uint16_t hint = cache->index;
- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, LOAD_ATTR);
- if (DK_IS_UNICODE(dict->ma_keys)) {
- PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
- DEOPT_IF(ep->me_key != name, LOAD_ATTR);
- res = ep->me_value;
- }
- else {
- PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint;
- DEOPT_IF(ep->me_key != name, LOAD_ATTR);
- res = ep->me_value;
- }
- DEOPT_IF(res == NULL, LOAD_ATTR);
- STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- SET_TOP(res);
- Py_DECREF(owner);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
- DISPATCH();
- }
-
- TARGET(LOAD_ATTR_SLOT) {
- assert(cframe.use_tracing == 0);
- PyObject *owner = TOP();
- PyObject *res;
- PyTypeObject *tp = Py_TYPE(owner);
- _PyAttrCache *cache = (_PyAttrCache *)next_instr;
- uint32_t type_version = read_u32(cache->version);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
- char *addr = (char *)owner + cache->index;
- res = *(PyObject **)addr;
- DEOPT_IF(res == NULL, LOAD_ATTR);
- STAT_INC(LOAD_ATTR, hit);
- Py_INCREF(res);
- SET_TOP(res);
- Py_DECREF(owner);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
- DISPATCH();
- }
-
- TARGET(STORE_ATTR_ADAPTIVE) {
- assert(cframe.use_tracing == 0);
- _PyAttrCache *cache = (_PyAttrCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- PyObject *owner = TOP();
- PyObject *name = GETITEM(names, oparg);
- next_instr--;
- if (_Py_Specialize_StoreAttr(owner, next_instr, name) < 0) {
- next_instr++;
- goto error;
- }
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(STORE_ATTR, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(STORE_ATTR);
- }
- }
-
- TARGET(STORE_ATTR_INSTANCE_VALUE) {
- assert(cframe.use_tracing == 0);
- PyObject *owner = TOP();
- PyTypeObject *tp = Py_TYPE(owner);
- _PyAttrCache *cache = (_PyAttrCache *)next_instr;
- uint32_t type_version = read_u32(cache->version);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
- assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictValues *values = *_PyObject_ValuesPointer(owner);
- DEOPT_IF(values == NULL, STORE_ATTR);
- STAT_INC(STORE_ATTR, hit);
- Py_ssize_t index = cache->index;
- STACK_SHRINK(1);
- PyObject *value = POP();
- PyObject *old_value = values->values[index];
- values->values[index] = value;
- if (old_value == NULL) {
- _PyDictValues_AddToInsertionOrder(values, index);
- }
- else {
- Py_DECREF(old_value);
- }
- Py_DECREF(owner);
- JUMPBY(INLINE_CACHE_ENTRIES_STORE_ATTR);
- DISPATCH();
- }
-
- TARGET(STORE_ATTR_WITH_HINT) {
- assert(cframe.use_tracing == 0);
- PyObject *owner = TOP();
- PyTypeObject *tp = Py_TYPE(owner);
- _PyAttrCache *cache = (_PyAttrCache *)next_instr;
- uint32_t type_version = read_u32(cache->version);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
- assert(tp->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictObject *dict = *(PyDictObject **)_PyObject_ManagedDictPointer(owner);
- DEOPT_IF(dict == NULL, STORE_ATTR);
- assert(PyDict_CheckExact((PyObject *)dict));
- PyObject *name = GETITEM(names, oparg);
- uint16_t hint = cache->index;
- DEOPT_IF(hint >= (size_t)dict->ma_keys->dk_nentries, STORE_ATTR);
- PyObject *value, *old_value;
- if (DK_IS_UNICODE(dict->ma_keys)) {
- PyDictUnicodeEntry *ep = DK_UNICODE_ENTRIES(dict->ma_keys) + hint;
- DEOPT_IF(ep->me_key != name, STORE_ATTR);
- old_value = ep->me_value;
- DEOPT_IF(old_value == NULL, STORE_ATTR);
- STACK_SHRINK(1);
- value = POP();
- ep->me_value = value;
- }
- else {
- PyDictKeyEntry *ep = DK_ENTRIES(dict->ma_keys) + hint;
- DEOPT_IF(ep->me_key != name, STORE_ATTR);
- old_value = ep->me_value;
- DEOPT_IF(old_value == NULL, STORE_ATTR);
- STACK_SHRINK(1);
- value = POP();
- ep->me_value = value;
- }
- Py_DECREF(old_value);
- STAT_INC(STORE_ATTR, hit);
- /* Ensure dict is GC tracked if it needs to be */
- if (!_PyObject_GC_IS_TRACKED(dict) && _PyObject_GC_MAY_BE_TRACKED(value)) {
- _PyObject_GC_TRACK(dict);
- }
- /* PEP 509 */
- dict->ma_version_tag = DICT_NEXT_VERSION();
- Py_DECREF(owner);
- JUMPBY(INLINE_CACHE_ENTRIES_STORE_ATTR);
- DISPATCH();
- }
-
- TARGET(STORE_ATTR_SLOT) {
- assert(cframe.use_tracing == 0);
- PyObject *owner = TOP();
- PyTypeObject *tp = Py_TYPE(owner);
- _PyAttrCache *cache = (_PyAttrCache *)next_instr;
- uint32_t type_version = read_u32(cache->version);
- assert(type_version != 0);
- DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
- char *addr = (char *)owner + cache->index;
- STAT_INC(STORE_ATTR, hit);
- STACK_SHRINK(1);
- PyObject *value = POP();
- PyObject *old_value = *(PyObject **)addr;
- *(PyObject **)addr = value;
- Py_XDECREF(old_value);
- Py_DECREF(owner);
- JUMPBY(INLINE_CACHE_ENTRIES_STORE_ATTR);
- DISPATCH();
- }
-
- TARGET(COMPARE_OP) {
- PREDICTED(COMPARE_OP);
- assert(oparg <= Py_GE);
- PyObject *right = POP();
- PyObject *left = TOP();
- PyObject *res = PyObject_RichCompare(left, right, oparg);
- SET_TOP(res);
- Py_DECREF(left);
- Py_DECREF(right);
- if (res == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_COMPARE_OP);
- DISPATCH();
- }
-
- TARGET(COMPARE_OP_ADAPTIVE) {
- assert(cframe.use_tracing == 0);
- _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- PyObject *right = TOP();
- PyObject *left = SECOND();
- next_instr--;
- _Py_Specialize_CompareOp(left, right, next_instr, oparg);
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(COMPARE_OP, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(COMPARE_OP);
- }
- }
-
- TARGET(COMPARE_OP_FLOAT_JUMP) {
- assert(cframe.use_tracing == 0);
- // Combined: COMPARE_OP (float ? float) + POP_JUMP_(direction)_IF_(true/false)
- _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
- int when_to_jump_mask = cache->mask;
- PyObject *right = TOP();
- PyObject *left = SECOND();
- DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP);
- DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP);
- double dleft = PyFloat_AS_DOUBLE(left);
- double dright = PyFloat_AS_DOUBLE(right);
- int sign = (dleft > dright) - (dleft < dright);
- DEOPT_IF(isnan(dleft), COMPARE_OP);
- DEOPT_IF(isnan(dright), COMPARE_OP);
- STAT_INC(COMPARE_OP, hit);
- JUMPBY(INLINE_CACHE_ENTRIES_COMPARE_OP);
- NEXTOPARG();
- STACK_SHRINK(2);
- _Py_DECREF_SPECIALIZED(left, _PyFloat_ExactDealloc);
- _Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
- assert(opcode == POP_JUMP_FORWARD_IF_FALSE ||
- opcode == POP_JUMP_BACKWARD_IF_FALSE ||
- opcode == POP_JUMP_FORWARD_IF_TRUE ||
- opcode == POP_JUMP_BACKWARD_IF_TRUE);
- int jump = (9 << (sign + 1)) & when_to_jump_mask;
- if (!jump) {
- next_instr++;
- }
- else if (jump >= 8) {
- assert(opcode == POP_JUMP_BACKWARD_IF_TRUE ||
- opcode == POP_JUMP_BACKWARD_IF_FALSE);
- JUMPBY(1 - oparg);
- CHECK_EVAL_BREAKER();
- }
- else {
- assert(opcode == POP_JUMP_FORWARD_IF_TRUE ||
- opcode == POP_JUMP_FORWARD_IF_FALSE);
- JUMPBY(1 + oparg);
- }
- DISPATCH();
- }
-
- TARGET(COMPARE_OP_INT_JUMP) {
- assert(cframe.use_tracing == 0);
- // Combined: COMPARE_OP (int ? int) + POP_JUMP_(direction)_IF_(true/false)
- _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
- int when_to_jump_mask = cache->mask;
- PyObject *right = TOP();
- PyObject *left = SECOND();
- DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP);
- DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP);
- DEOPT_IF((size_t)(Py_SIZE(left) + 1) > 2, COMPARE_OP);
- DEOPT_IF((size_t)(Py_SIZE(right) + 1) > 2, COMPARE_OP);
- STAT_INC(COMPARE_OP, hit);
- assert(Py_ABS(Py_SIZE(left)) <= 1 && Py_ABS(Py_SIZE(right)) <= 1);
- Py_ssize_t ileft = Py_SIZE(left) * ((PyLongObject *)left)->ob_digit[0];
- Py_ssize_t iright = Py_SIZE(right) * ((PyLongObject *)right)->ob_digit[0];
- int sign = (ileft > iright) - (ileft < iright);
- JUMPBY(INLINE_CACHE_ENTRIES_COMPARE_OP);
- NEXTOPARG();
- STACK_SHRINK(2);
- _Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
- _Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
- assert(opcode == POP_JUMP_FORWARD_IF_FALSE ||
- opcode == POP_JUMP_BACKWARD_IF_FALSE ||
- opcode == POP_JUMP_FORWARD_IF_TRUE ||
- opcode == POP_JUMP_BACKWARD_IF_TRUE);
- int jump = (9 << (sign + 1)) & when_to_jump_mask;
- if (!jump) {
- next_instr++;
- }
- else if (jump >= 8) {
- assert(opcode == POP_JUMP_BACKWARD_IF_TRUE ||
- opcode == POP_JUMP_BACKWARD_IF_FALSE);
- JUMPBY(1 - oparg);
- CHECK_EVAL_BREAKER();
- }
- else {
- assert(opcode == POP_JUMP_FORWARD_IF_TRUE ||
- opcode == POP_JUMP_FORWARD_IF_FALSE);
- JUMPBY(1 + oparg);
- }
- DISPATCH();
- }
-
- TARGET(COMPARE_OP_STR_JUMP) {
- assert(cframe.use_tracing == 0);
- // Combined: COMPARE_OP (str == str or str != str) + POP_JUMP_(direction)_IF_(true/false)
- _PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
- int when_to_jump_mask = cache->mask;
- PyObject *right = TOP();
- PyObject *left = SECOND();
- DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP);
- DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP);
- STAT_INC(COMPARE_OP, hit);
- int res = _PyUnicode_Equal(left, right);
- if (res < 0) {
- goto error;
- }
- assert(oparg == Py_EQ || oparg == Py_NE);
- JUMPBY(INLINE_CACHE_ENTRIES_COMPARE_OP);
- NEXTOPARG();
- assert(opcode == POP_JUMP_FORWARD_IF_FALSE ||
- opcode == POP_JUMP_BACKWARD_IF_FALSE ||
- opcode == POP_JUMP_FORWARD_IF_TRUE ||
- opcode == POP_JUMP_BACKWARD_IF_TRUE);
- STACK_SHRINK(2);
- _Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
- _Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
- assert(res == 0 || res == 1);
- int sign = 1 - res;
- int jump = (9 << (sign + 1)) & when_to_jump_mask;
- if (!jump) {
- next_instr++;
- }
- else if (jump >= 8) {
- assert(opcode == POP_JUMP_BACKWARD_IF_TRUE ||
- opcode == POP_JUMP_BACKWARD_IF_FALSE);
- JUMPBY(1 - oparg);
- CHECK_EVAL_BREAKER();
- }
- else {
- assert(opcode == POP_JUMP_FORWARD_IF_TRUE ||
- opcode == POP_JUMP_FORWARD_IF_FALSE);
- JUMPBY(1 + oparg);
- }
- DISPATCH();
- }
-
- TARGET(IS_OP) {
- PyObject *right = POP();
- PyObject *left = TOP();
- int res = Py_Is(left, right) ^ oparg;
- PyObject *b = res ? Py_True : Py_False;
- Py_INCREF(b);
- SET_TOP(b);
- Py_DECREF(left);
- Py_DECREF(right);
- DISPATCH();
- }
-
- TARGET(CONTAINS_OP) {
- PyObject *right = POP();
- PyObject *left = POP();
- int res = PySequence_Contains(right, left);
- Py_DECREF(left);
- Py_DECREF(right);
- if (res < 0) {
- goto error;
- }
- PyObject *b = (res^oparg) ? Py_True : Py_False;
- Py_INCREF(b);
- PUSH(b);
- DISPATCH();
- }
-
- TARGET(CHECK_EG_MATCH) {
- PyObject *match_type = POP();
- if (check_except_star_type_valid(tstate, match_type) < 0) {
- Py_DECREF(match_type);
- goto error;
- }
-
- PyObject *exc_value = TOP();
- PyObject *match = NULL, *rest = NULL;
- int res = exception_group_match(exc_value, match_type,
- &match, &rest);
- Py_DECREF(match_type);
- if (res < 0) {
- goto error;
- }
-
- if (match == NULL || rest == NULL) {
- assert(match == NULL);
- assert(rest == NULL);
- goto error;
- }
- if (Py_IsNone(match)) {
- PUSH(match);
- Py_XDECREF(rest);
- }
- else {
- /* Total or partial match - update the stack from
- * [val]
- * to
- * [rest, match]
- * (rest can be Py_None)
- */
-
- SET_TOP(rest);
- PUSH(match);
- PyErr_SetExcInfo(NULL, Py_NewRef(match), NULL);
- Py_DECREF(exc_value);
- }
- DISPATCH();
- }
-
- TARGET(CHECK_EXC_MATCH) {
- PyObject *right = POP();
- PyObject *left = TOP();
- assert(PyExceptionInstance_Check(left));
- if (check_except_type_valid(tstate, right) < 0) {
- Py_DECREF(right);
- goto error;
- }
-
- int res = PyErr_GivenExceptionMatches(left, right);
- Py_DECREF(right);
- PUSH(Py_NewRef(res ? Py_True : Py_False));
- DISPATCH();
- }
-
- TARGET(IMPORT_NAME) {
- PyObject *name = GETITEM(names, oparg);
- PyObject *fromlist = POP();
- PyObject *level = TOP();
- PyObject *res;
- res = import_name(tstate, frame, name, fromlist, level);
- Py_DECREF(level);
- Py_DECREF(fromlist);
- SET_TOP(res);
- if (res == NULL)
- goto error;
- DISPATCH();
- }
-
- TARGET(IMPORT_STAR) {
- PyObject *from = POP(), *locals;
- int err;
- if (_PyFrame_FastToLocalsWithError(frame) < 0) {
- Py_DECREF(from);
- goto error;
- }
-
- locals = LOCALS();
- if (locals == NULL) {
- _PyErr_SetString(tstate, PyExc_SystemError,
- "no locals found during 'import *'");
- Py_DECREF(from);
- goto error;
- }
- err = import_all_from(tstate, locals, from);
- _PyFrame_LocalsToFast(frame, 0);
- Py_DECREF(from);
- if (err != 0)
- goto error;
- DISPATCH();
- }
-
- TARGET(IMPORT_FROM) {
- PyObject *name = GETITEM(names, oparg);
- PyObject *from = TOP();
- PyObject *res;
- res = import_from(tstate, from, name);
- PUSH(res);
- if (res == NULL)
- goto error;
- DISPATCH();
- }
-
- TARGET(JUMP_FORWARD) {
- JUMPBY(oparg);
- DISPATCH();
- }
-
- TARGET(JUMP_BACKWARD) {
- _PyCode_Warmup(frame->f_code);
- JUMP_TO_INSTRUCTION(JUMP_BACKWARD_QUICK);
- }
-
- TARGET(POP_JUMP_BACKWARD_IF_FALSE) {
- PREDICTED(POP_JUMP_BACKWARD_IF_FALSE);
- PyObject *cond = POP();
- if (Py_IsTrue(cond)) {
- _Py_DECREF_NO_DEALLOC(cond);
- DISPATCH();
- }
- if (Py_IsFalse(cond)) {
- _Py_DECREF_NO_DEALLOC(cond);
- JUMPBY(-oparg);
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
- int err = PyObject_IsTrue(cond);
- Py_DECREF(cond);
- if (err > 0)
- ;
- else if (err == 0) {
- JUMPBY(-oparg);
- CHECK_EVAL_BREAKER();
- }
- else
- goto error;
- DISPATCH();
- }
-
- TARGET(POP_JUMP_FORWARD_IF_FALSE) {
- PREDICTED(POP_JUMP_FORWARD_IF_FALSE);
- PyObject *cond = POP();
- if (Py_IsTrue(cond)) {
- _Py_DECREF_NO_DEALLOC(cond);
- }
- else if (Py_IsFalse(cond)) {
- _Py_DECREF_NO_DEALLOC(cond);
- JUMPBY(oparg);
- }
- else {
- int err = PyObject_IsTrue(cond);
- Py_DECREF(cond);
- if (err > 0)
- ;
- else if (err == 0) {
- JUMPBY(oparg);
- }
- else
- goto error;
- }
- DISPATCH();
- }
-
- TARGET(POP_JUMP_BACKWARD_IF_TRUE) {
- PyObject *cond = POP();
- if (Py_IsFalse(cond)) {
- _Py_DECREF_NO_DEALLOC(cond);
- DISPATCH();
- }
- if (Py_IsTrue(cond)) {
- _Py_DECREF_NO_DEALLOC(cond);
- JUMPBY(-oparg);
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
- int err = PyObject_IsTrue(cond);
- Py_DECREF(cond);
- if (err > 0) {
- JUMPBY(-oparg);
- CHECK_EVAL_BREAKER();
- }
- else if (err == 0)
- ;
- else
- goto error;
- DISPATCH();
- }
-
- TARGET(POP_JUMP_FORWARD_IF_TRUE) {
- PyObject *cond = POP();
- if (Py_IsFalse(cond)) {
- _Py_DECREF_NO_DEALLOC(cond);
- }
- else if (Py_IsTrue(cond)) {
- _Py_DECREF_NO_DEALLOC(cond);
- JUMPBY(oparg);
- }
- else {
- int err = PyObject_IsTrue(cond);
- Py_DECREF(cond);
- if (err > 0) {
- JUMPBY(oparg);
- }
- else if (err == 0)
- ;
- else
- goto error;
- }
- DISPATCH();
- }
-
- TARGET(POP_JUMP_BACKWARD_IF_NOT_NONE) {
- PyObject *value = POP();
- if (!Py_IsNone(value)) {
- Py_DECREF(value);
- JUMPBY(-oparg);
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
- _Py_DECREF_NO_DEALLOC(value);
- DISPATCH();
- }
-
- TARGET(POP_JUMP_FORWARD_IF_NOT_NONE) {
- PyObject *value = POP();
- if (!Py_IsNone(value)) {
- JUMPBY(oparg);
- }
- Py_DECREF(value);
- DISPATCH();
- }
-
- TARGET(POP_JUMP_BACKWARD_IF_NONE) {
- PyObject *value = POP();
- if (Py_IsNone(value)) {
- _Py_DECREF_NO_DEALLOC(value);
- JUMPBY(-oparg);
- CHECK_EVAL_BREAKER();
- }
- else {
- Py_DECREF(value);
- }
- DISPATCH();
- }
-
- TARGET(POP_JUMP_FORWARD_IF_NONE) {
- PyObject *value = POP();
- if (Py_IsNone(value)) {
- _Py_DECREF_NO_DEALLOC(value);
- JUMPBY(oparg);
- }
- else {
- Py_DECREF(value);
- }
- DISPATCH();
- }
-
- TARGET(JUMP_IF_FALSE_OR_POP) {
- PyObject *cond = TOP();
- int err;
- if (Py_IsTrue(cond)) {
- STACK_SHRINK(1);
- _Py_DECREF_NO_DEALLOC(cond);
- DISPATCH();
- }
- if (Py_IsFalse(cond)) {
- JUMPBY(oparg);
- DISPATCH();
- }
- err = PyObject_IsTrue(cond);
- if (err > 0) {
- STACK_SHRINK(1);
- Py_DECREF(cond);
- }
- else if (err == 0)
- JUMPBY(oparg);
- else
- goto error;
- DISPATCH();
- }
-
- TARGET(JUMP_IF_TRUE_OR_POP) {
- PyObject *cond = TOP();
- int err;
- if (Py_IsFalse(cond)) {
- STACK_SHRINK(1);
- _Py_DECREF_NO_DEALLOC(cond);
- DISPATCH();
- }
- if (Py_IsTrue(cond)) {
- JUMPBY(oparg);
- DISPATCH();
- }
- err = PyObject_IsTrue(cond);
- if (err > 0) {
- JUMPBY(oparg);
- }
- else if (err == 0) {
- STACK_SHRINK(1);
- Py_DECREF(cond);
- }
- else
- goto error;
- DISPATCH();
- }
-
- TARGET(JUMP_BACKWARD_NO_INTERRUPT) {
- /* This bytecode is used in the `yield from` or `await` loop.
- * If there is an interrupt, we want it handled in the innermost
- * generator or coroutine, so we deliberately do not check it here.
- * (see bpo-30039).
- */
- JUMPBY(-oparg);
- DISPATCH();
- }
-
- TARGET(JUMP_BACKWARD_QUICK) {
- PREDICTED(JUMP_BACKWARD_QUICK);
- assert(oparg < INSTR_OFFSET());
- JUMPBY(-oparg);
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(GET_LEN) {
- // PUSH(len(TOS))
- Py_ssize_t len_i = PyObject_Length(TOP());
- if (len_i < 0) {
- goto error;
- }
- PyObject *len_o = PyLong_FromSsize_t(len_i);
- if (len_o == NULL) {
- goto error;
- }
- PUSH(len_o);
- DISPATCH();
- }
-
- TARGET(MATCH_CLASS) {
- // Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or
- // None on failure.
- PyObject *names = POP();
- PyObject *type = POP();
- PyObject *subject = TOP();
- assert(PyTuple_CheckExact(names));
- PyObject *attrs = match_class(tstate, subject, type, oparg, names);
- Py_DECREF(names);
- Py_DECREF(type);
- if (attrs) {
- // Success!
- assert(PyTuple_CheckExact(attrs));
- SET_TOP(attrs);
- }
- else if (_PyErr_Occurred(tstate)) {
- // Error!
- goto error;
- }
- else {
- // Failure!
- Py_INCREF(Py_None);
- SET_TOP(Py_None);
- }
- Py_DECREF(subject);
- DISPATCH();
- }
-
- TARGET(MATCH_MAPPING) {
- PyObject *subject = TOP();
- int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING;
- PyObject *res = match ? Py_True : Py_False;
- Py_INCREF(res);
- PUSH(res);
- PREDICT(POP_JUMP_FORWARD_IF_FALSE);
- PREDICT(POP_JUMP_BACKWARD_IF_FALSE);
- DISPATCH();
- }
-
- TARGET(MATCH_SEQUENCE) {
- PyObject *subject = TOP();
- int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE;
- PyObject *res = match ? Py_True : Py_False;
- Py_INCREF(res);
- PUSH(res);
- PREDICT(POP_JUMP_FORWARD_IF_FALSE);
- PREDICT(POP_JUMP_BACKWARD_IF_FALSE);
- DISPATCH();
- }
-
- TARGET(MATCH_KEYS) {
- // On successful match, PUSH(values). Otherwise, PUSH(None).
- PyObject *keys = TOP();
- PyObject *subject = SECOND();
- PyObject *values_or_none = match_keys(tstate, subject, keys);
- if (values_or_none == NULL) {
- goto error;
- }
- PUSH(values_or_none);
- DISPATCH();
- }
-
- TARGET(GET_ITER) {
- /* before: [obj]; after [getiter(obj)] */
- PyObject *iterable = TOP();
- PyObject *iter = PyObject_GetIter(iterable);
- Py_DECREF(iterable);
- SET_TOP(iter);
- if (iter == NULL)
- goto error;
- PREDICT(FOR_ITER);
- DISPATCH();
- }
-
- TARGET(GET_YIELD_FROM_ITER) {
- /* before: [obj]; after [getiter(obj)] */
- PyObject *iterable = TOP();
- PyObject *iter;
- if (PyCoro_CheckExact(iterable)) {
- /* `iterable` is a coroutine */
- if (!(frame->f_code->co_flags & (CO_COROUTINE | CO_ITERABLE_COROUTINE))) {
- /* and it is used in a 'yield from' expression of a
- regular generator. */
- Py_DECREF(iterable);
- SET_TOP(NULL);
- _PyErr_SetString(tstate, PyExc_TypeError,
- "cannot 'yield from' a coroutine object "
- "in a non-coroutine generator");
- goto error;
- }
- }
- else if (!PyGen_CheckExact(iterable)) {
- /* `iterable` is not a generator. */
- iter = PyObject_GetIter(iterable);
- Py_DECREF(iterable);
- SET_TOP(iter);
- if (iter == NULL)
- goto error;
- }
- PREDICT(LOAD_CONST);
- DISPATCH();
- }
-
- TARGET(FOR_ITER) {
- PREDICTED(FOR_ITER);
- /* before: [iter]; after: [iter, iter()] *or* [] */
- PyObject *iter = TOP();
-#ifdef Py_STATS
- extern int _PySpecialization_ClassifyIterator(PyObject *);
- _py_stats.opcode_stats[FOR_ITER].specialization.failure++;
- _py_stats.opcode_stats[FOR_ITER].specialization.failure_kinds[_PySpecialization_ClassifyIterator(iter)]++;
+ switch (opcode)
#endif
- PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
- if (next != NULL) {
- PUSH(next);
- PREDICT(STORE_FAST);
- PREDICT(UNPACK_SEQUENCE);
- DISPATCH();
- }
- if (_PyErr_Occurred(tstate)) {
- if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
- goto error;
- }
- else if (tstate->c_tracefunc != NULL) {
- call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
- }
- _PyErr_Clear(tstate);
- }
- /* iterator ended normally */
- STACK_SHRINK(1);
- Py_DECREF(iter);
- JUMPBY(oparg);
- DISPATCH();
- }
-
- TARGET(BEFORE_ASYNC_WITH) {
- PyObject *mgr = TOP();
- PyObject *res;
- PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__));
- if (enter == NULL) {
- if (!_PyErr_Occurred(tstate)) {
- _PyErr_Format(tstate, PyExc_TypeError,
- "'%.200s' object does not support the "
- "asynchronous context manager protocol",
- Py_TYPE(mgr)->tp_name);
- }
- goto error;
- }
- PyObject *exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__aexit__));
- if (exit == NULL) {
- if (!_PyErr_Occurred(tstate)) {
- _PyErr_Format(tstate, PyExc_TypeError,
- "'%.200s' object does not support the "
- "asynchronous context manager protocol "
- "(missed __aexit__ method)",
- Py_TYPE(mgr)->tp_name);
- }
- Py_DECREF(enter);
- goto error;
- }
- SET_TOP(exit);
- Py_DECREF(mgr);
- res = _PyObject_CallNoArgs(enter);
- Py_DECREF(enter);
- if (res == NULL)
- goto error;
- PUSH(res);
- PREDICT(GET_AWAITABLE);
- DISPATCH();
- }
-
- TARGET(BEFORE_WITH) {
- PyObject *mgr = TOP();
- PyObject *res;
- PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__enter__));
- if (enter == NULL) {
- if (!_PyErr_Occurred(tstate)) {
- _PyErr_Format(tstate, PyExc_TypeError,
- "'%.200s' object does not support the "
- "context manager protocol",
- Py_TYPE(mgr)->tp_name);
- }
- goto error;
- }
- PyObject *exit = _PyObject_LookupSpecial(mgr, &_Py_ID(__exit__));
- if (exit == NULL) {
- if (!_PyErr_Occurred(tstate)) {
- _PyErr_Format(tstate, PyExc_TypeError,
- "'%.200s' object does not support the "
- "context manager protocol "
- "(missed __exit__ method)",
- Py_TYPE(mgr)->tp_name);
- }
- Py_DECREF(enter);
- goto error;
- }
- SET_TOP(exit);
- Py_DECREF(mgr);
- res = _PyObject_CallNoArgs(enter);
- Py_DECREF(enter);
- if (res == NULL) {
- goto error;
- }
- PUSH(res);
- DISPATCH();
- }
-
- TARGET(WITH_EXCEPT_START) {
- /* At the top of the stack are 4 values:
- - TOP = exc_info()
- - SECOND = previous exception
- - THIRD: lasti of exception in exc_info()
- - FOURTH: the context.__exit__ bound method
- We call FOURTH(type(TOP), TOP, GetTraceback(TOP)).
- Then we push the __exit__ return value.
- */
- PyObject *exit_func;
- PyObject *exc, *val, *tb, *res;
-
- val = TOP();
- assert(val && PyExceptionInstance_Check(val));
- exc = PyExceptionInstance_Class(val);
- tb = PyException_GetTraceback(val);
- Py_XDECREF(tb);
- assert(PyLong_Check(PEEK(3)));
- exit_func = PEEK(4);
- PyObject *stack[4] = {NULL, exc, val, tb};
- res = PyObject_Vectorcall(exit_func, stack + 1,
- 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
- if (res == NULL)
- goto error;
-
- PUSH(res);
- DISPATCH();
- }
-
- TARGET(PUSH_EXC_INFO) {
- PyObject *value = TOP();
-
- _PyErr_StackItem *exc_info = tstate->exc_info;
- if (exc_info->exc_value != NULL) {
- SET_TOP(exc_info->exc_value);
- }
- else {
- Py_INCREF(Py_None);
- SET_TOP(Py_None);
- }
-
- Py_INCREF(value);
- PUSH(value);
- assert(PyExceptionInstance_Check(value));
- exc_info->exc_value = value;
-
- DISPATCH();
- }
-
- TARGET(LOAD_METHOD) {
- PREDICTED(LOAD_METHOD);
- /* Designed to work in tandem with PRECALL. */
- PyObject *name = GETITEM(names, oparg);
- PyObject *obj = TOP();
- PyObject *meth = NULL;
-
- int meth_found = _PyObject_GetMethod(obj, name, &meth);
-
- if (meth == NULL) {
- /* Most likely attribute wasn't found. */
- goto error;
- }
-
- if (meth_found) {
- /* We can bypass temporary bound method object.
- meth is unbound method and obj is self.
-
- meth | self | arg1 | ... | argN
- */
- SET_TOP(meth);
- PUSH(obj); // self
- }
- else {
- /* meth is not an unbound method (but a regular attr, or
- something was returned by a descriptor protocol). Set
- the second element of the stack to NULL, to signal
- PRECALL that it's not a method call.
-
- NULL | meth | arg1 | ... | argN
- */
- SET_TOP(NULL);
- Py_DECREF(obj);
- PUSH(meth);
- }
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_METHOD);
- DISPATCH();
- }
-
- TARGET(LOAD_METHOD_ADAPTIVE) {
- assert(cframe.use_tracing == 0);
- _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- PyObject *owner = TOP();
- PyObject *name = GETITEM(names, oparg);
- next_instr--;
- if (_Py_Specialize_LoadMethod(owner, next_instr, name) < 0) {
- next_instr++;
- goto error;
- }
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(LOAD_METHOD, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(LOAD_METHOD);
- }
- }
-
- TARGET(LOAD_METHOD_WITH_VALUES) {
- /* LOAD_METHOD, with cached method object */
- assert(cframe.use_tracing == 0);
- PyObject *self = TOP();
- PyTypeObject *self_cls = Py_TYPE(self);
- _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
- uint32_t type_version = read_u32(cache->type_version);
- assert(type_version != 0);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_METHOD);
- assert(self_cls->tp_flags & Py_TPFLAGS_MANAGED_DICT);
- PyDictObject *dict = *(PyDictObject**)_PyObject_ManagedDictPointer(self);
- DEOPT_IF(dict != NULL, LOAD_METHOD);
- PyHeapTypeObject *self_heap_type = (PyHeapTypeObject *)self_cls;
- DEOPT_IF(self_heap_type->ht_cached_keys->dk_version !=
- read_u32(cache->keys_version), LOAD_METHOD);
- STAT_INC(LOAD_METHOD, hit);
- PyObject *res = read_obj(cache->descr);
- assert(res != NULL);
- assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR));
- Py_INCREF(res);
- SET_TOP(res);
- PUSH(self);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_METHOD);
- DISPATCH();
- }
-
- TARGET(LOAD_METHOD_WITH_DICT) {
- /* LOAD_METHOD, with a dict
- Can be either a managed dict, or a tp_dictoffset offset.*/
- assert(cframe.use_tracing == 0);
- PyObject *self = TOP();
- PyTypeObject *self_cls = Py_TYPE(self);
- _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
-
- DEOPT_IF(self_cls->tp_version_tag != read_u32(cache->type_version),
- LOAD_METHOD);
- /* Treat index as a signed 16 bit value */
- int dictoffset = *(int16_t *)&cache->dict_offset;
- PyDictObject **dictptr = (PyDictObject**)(((char *)self)+dictoffset);
- assert(
- dictoffset == MANAGED_DICT_OFFSET ||
- (dictoffset == self_cls->tp_dictoffset && dictoffset > 0)
- );
- PyDictObject *dict = *dictptr;
- DEOPT_IF(dict == NULL, LOAD_METHOD);
- DEOPT_IF(dict->ma_keys->dk_version != read_u32(cache->keys_version),
- LOAD_METHOD);
- STAT_INC(LOAD_METHOD, hit);
- PyObject *res = read_obj(cache->descr);
- assert(res != NULL);
- assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR));
- Py_INCREF(res);
- SET_TOP(res);
- PUSH(self);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_METHOD);
- DISPATCH();
- }
-
- TARGET(LOAD_METHOD_NO_DICT) {
- assert(cframe.use_tracing == 0);
- PyObject *self = TOP();
- PyTypeObject *self_cls = Py_TYPE(self);
- _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
- uint32_t type_version = read_u32(cache->type_version);
- DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_METHOD);
- assert(self_cls->tp_dictoffset == 0);
- STAT_INC(LOAD_METHOD, hit);
- PyObject *res = read_obj(cache->descr);
- assert(res != NULL);
- assert(_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR));
- Py_INCREF(res);
- SET_TOP(res);
- PUSH(self);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_METHOD);
- DISPATCH();
- }
-
- TARGET(LOAD_METHOD_MODULE) {
- /* LOAD_METHOD, for module methods */
- assert(cframe.use_tracing == 0);
- PyObject *owner = TOP();
- PyObject *res;
- LOAD_MODULE_ATTR_OR_METHOD(METHOD);
- SET_TOP(NULL);
- Py_DECREF(owner);
- PUSH(res);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_METHOD);
- DISPATCH();
- }
-
- TARGET(LOAD_METHOD_CLASS) {
- /* LOAD_METHOD, for class methods */
- assert(cframe.use_tracing == 0);
- _PyLoadMethodCache *cache = (_PyLoadMethodCache *)next_instr;
-
- PyObject *cls = TOP();
- DEOPT_IF(!PyType_Check(cls), LOAD_METHOD);
- uint32_t type_version = read_u32(cache->type_version);
- DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version,
- LOAD_METHOD);
- assert(type_version != 0);
-
- STAT_INC(LOAD_METHOD, hit);
- PyObject *res = read_obj(cache->descr);
- assert(res != NULL);
- Py_INCREF(res);
- SET_TOP(NULL);
- Py_DECREF(cls);
- PUSH(res);
- JUMPBY(INLINE_CACHE_ENTRIES_LOAD_METHOD);
- DISPATCH();
- }
-
- TARGET(PRECALL) {
- PREDICTED(PRECALL);
- /* Designed to work in tamdem with LOAD_METHOD. */
- /* `meth` is NULL when LOAD_METHOD thinks that it's not
- a method call.
-
- Stack layout:
-
- ... | NULL | callable | arg1 | ... | argN
- ^- TOP()
- ^- (-oparg)
- ^- (-oparg-1)
- ^- (-oparg-2)
-
- `callable` will be POPed by call_function.
- NULL will will be POPed manually later.
- If `meth` isn't NULL, it's a method call. Stack layout:
-
- ... | method | self | arg1 | ... | argN
- ^- TOP()
- ^- (-oparg)
- ^- (-oparg-1)
- ^- (-oparg-2)
-
- `self` and `method` will be POPed by call_function.
- We'll be passing `oparg + 1` to call_function, to
- make it accept the `self` as a first argument.
- */
- int is_meth = is_method(stack_pointer, oparg);
- int nargs = oparg + is_meth;
- /* Move ownership of reference from stack to call_shape
- * and make sure that NULL is cleared from stack */
- PyObject *function = PEEK(nargs + 1);
- if (!is_meth && Py_TYPE(function) == &PyMethod_Type) {
- PyObject *meth = ((PyMethodObject *)function)->im_func;
- PyObject *self = ((PyMethodObject *)function)->im_self;
- Py_INCREF(meth);
- Py_INCREF(self);
- PEEK(oparg+1) = self;
- PEEK(oparg+2) = meth;
- Py_DECREF(function);
- }
- JUMPBY(INLINE_CACHE_ENTRIES_PRECALL);
- DISPATCH();
- }
-
- TARGET(PRECALL_BOUND_METHOD) {
- DEOPT_IF(is_method(stack_pointer, oparg), PRECALL);
- PyObject *function = PEEK(oparg + 1);
- DEOPT_IF(Py_TYPE(function) != &PyMethod_Type, PRECALL);
- STAT_INC(PRECALL, hit);
- PyObject *meth = ((PyMethodObject *)function)->im_func;
- PyObject *self = ((PyMethodObject *)function)->im_self;
- Py_INCREF(meth);
- Py_INCREF(self);
- PEEK(oparg + 1) = self;
- PEEK(oparg + 2) = meth;
- Py_DECREF(function);
- JUMPBY(INLINE_CACHE_ENTRIES_PRECALL);
- DISPATCH();
- }
-
- TARGET(PRECALL_PYFUNC) {
- int nargs = oparg + is_method(stack_pointer, oparg);
- PyObject *function = PEEK(nargs + 1);
- DEOPT_IF(Py_TYPE(function) != &PyFunction_Type, PRECALL);
- STAT_INC(PRECALL, hit);
- JUMPBY(INLINE_CACHE_ENTRIES_PRECALL);
- DISPATCH();
- }
-
- TARGET(KW_NAMES) {
- assert(call_shape.kwnames == NULL);
- assert(oparg < PyTuple_GET_SIZE(consts));
- call_shape.kwnames = GETITEM(consts, oparg);
- DISPATCH();
- }
-
- TARGET(CALL) {
- int is_meth;
- call_function:
- is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- PyObject *function = PEEK(total_args + 1);
- int positional_args = total_args - KWNAMES_LEN();
- // Check if the call can be inlined or not
- if (Py_TYPE(function) == &PyFunction_Type && tstate->interp->eval_frame == NULL) {
- int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(function))->co_flags;
- PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : PyFunction_GET_GLOBALS(function);
- STACK_SHRINK(total_args);
- _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
- tstate, (PyFunctionObject *)function, locals,
- stack_pointer, positional_args, call_shape.kwnames
- );
- call_shape.kwnames = NULL;
- STACK_SHRINK(2-is_meth);
- // The frame has stolen all the arguments from the stack,
- // so there is no need to clean them up.
- if (new_frame == NULL) {
- goto error;
- }
- _PyFrame_SetStackPointer(frame, stack_pointer);
- JUMPBY(INLINE_CACHE_ENTRIES_CALL);
- frame->prev_instr = next_instr - 1;
- new_frame->previous = frame;
- cframe.current_frame = frame = new_frame;
- CALL_STAT_INC(inlined_py_calls);
- goto start_frame;
- }
- /* Callable is not a normal Python function */
- PyObject *res;
- if (cframe.use_tracing) {
- res = trace_call_function(
- tstate, function, stack_pointer-total_args,
- positional_args, call_shape.kwnames);
- }
- else {
- res = PyObject_Vectorcall(
- function, stack_pointer-total_args,
- positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
- call_shape.kwnames);
- }
- call_shape.kwnames = NULL;
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
- Py_DECREF(function);
- /* Clear the stack */
- STACK_SHRINK(total_args);
- for (int i = 0; i < total_args; i++) {
- Py_DECREF(stack_pointer[i]);
- }
- STACK_SHRINK(2-is_meth);
- PUSH(res);
- if (res == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_CALL);
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_ADAPTIVE) {
- _PyPrecallCache *cache = (_PyPrecallCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- next_instr--;
- int is_meth = is_method(stack_pointer, oparg);
- int nargs = oparg + is_meth;
- PyObject *callable = PEEK(nargs + 1);
- int err = _Py_Specialize_Precall(callable, next_instr, nargs,
- call_shape.kwnames, oparg);
- if (err < 0) {
- next_instr++;
- goto error;
- }
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(PRECALL, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(PRECALL);
- }
- }
-
- TARGET(CALL_ADAPTIVE) {
- _PyCallCache *cache = (_PyCallCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- next_instr--;
- int is_meth = is_method(stack_pointer, oparg);
- int nargs = oparg + is_meth;
- PyObject *callable = PEEK(nargs + 1);
- int err = _Py_Specialize_Call(callable, next_instr, nargs,
- call_shape.kwnames);
- if (err < 0) {
- next_instr++;
- goto error;
- }
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(CALL, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- goto call_function;
- }
- }
-
- TARGET(CALL_PY_EXACT_ARGS) {
- assert(call_shape.kwnames == NULL);
- DEOPT_IF(tstate->interp->eval_frame, CALL);
- _PyCallCache *cache = (_PyCallCache *)next_instr;
- int is_meth = is_method(stack_pointer, oparg);
- int argcount = oparg + is_meth;
- PyObject *callable = PEEK(argcount + 1);
- DEOPT_IF(!PyFunction_Check(callable), CALL);
- PyFunctionObject *func = (PyFunctionObject *)callable;
- DEOPT_IF(func->func_version != read_u32(cache->func_version), CALL);
- PyCodeObject *code = (PyCodeObject *)func->func_code;
- DEOPT_IF(code->co_argcount != argcount, CALL);
- STAT_INC(CALL, hit);
- _PyInterpreterFrame *new_frame = _PyFrame_Push(tstate, func);
- if (new_frame == NULL) {
- goto error;
- }
- CALL_STAT_INC(inlined_py_calls);
- STACK_SHRINK(argcount);
- for (int i = 0; i < argcount; i++) {
- new_frame->localsplus[i] = stack_pointer[i];
- }
- for (int i = argcount; i < code->co_nlocalsplus; i++) {
- new_frame->localsplus[i] = NULL;
- }
- STACK_SHRINK(2-is_meth);
- _PyFrame_SetStackPointer(frame, stack_pointer);
- JUMPBY(INLINE_CACHE_ENTRIES_CALL);
- frame->prev_instr = next_instr - 1;
- new_frame->previous = frame;
- frame = cframe.current_frame = new_frame;
- goto start_frame;
- }
-
- TARGET(CALL_PY_WITH_DEFAULTS) {
- assert(call_shape.kwnames == NULL);
- DEOPT_IF(tstate->interp->eval_frame, CALL);
- _PyCallCache *cache = (_PyCallCache *)next_instr;
- int is_meth = is_method(stack_pointer, oparg);
- int argcount = oparg + is_meth;
- PyObject *callable = PEEK(argcount + 1);
- DEOPT_IF(!PyFunction_Check(callable), CALL);
- PyFunctionObject *func = (PyFunctionObject *)callable;
- DEOPT_IF(func->func_version != read_u32(cache->func_version), CALL);
- PyCodeObject *code = (PyCodeObject *)func->func_code;
- DEOPT_IF(argcount > code->co_argcount, CALL);
- int minargs = cache->min_args;
- DEOPT_IF(argcount < minargs, CALL);
- STAT_INC(CALL, hit);
- _PyInterpreterFrame *new_frame = _PyFrame_Push(tstate, func);
- if (new_frame == NULL) {
- goto error;
- }
- CALL_STAT_INC(inlined_py_calls);
- STACK_SHRINK(argcount);
- for (int i = 0; i < argcount; i++) {
- new_frame->localsplus[i] = stack_pointer[i];
- }
- for (int i = argcount; i < code->co_argcount; i++) {
- PyObject *def = PyTuple_GET_ITEM(func->func_defaults,
- i - minargs);
- Py_INCREF(def);
- new_frame->localsplus[i] = def;
- }
- for (int i = code->co_argcount; i < code->co_nlocalsplus; i++) {
- new_frame->localsplus[i] = NULL;
- }
- STACK_SHRINK(2-is_meth);
- _PyFrame_SetStackPointer(frame, stack_pointer);
- JUMPBY(INLINE_CACHE_ENTRIES_CALL);
- frame->prev_instr = next_instr - 1;
- new_frame->previous = frame;
- frame = cframe.current_frame = new_frame;
- goto start_frame;
- }
-
- TARGET(PRECALL_NO_KW_TYPE_1) {
- assert(call_shape.kwnames == NULL);
- assert(cframe.use_tracing == 0);
- assert(oparg == 1);
- DEOPT_IF(is_method(stack_pointer, 1), PRECALL);
- PyObject *obj = TOP();
- PyObject *callable = SECOND();
- DEOPT_IF(callable != (PyObject *)&PyType_Type, PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- PyObject *res = Py_NewRef(Py_TYPE(obj));
- Py_DECREF(callable);
- Py_DECREF(obj);
- STACK_SHRINK(2);
- SET_TOP(res);
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_STR_1) {
- assert(call_shape.kwnames == NULL);
- assert(cframe.use_tracing == 0);
- assert(oparg == 1);
- DEOPT_IF(is_method(stack_pointer, 1), PRECALL);
- PyObject *callable = PEEK(2);
- DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- PyObject *arg = TOP();
- PyObject *res = PyObject_Str(arg);
- Py_DECREF(arg);
- Py_DECREF(&PyUnicode_Type);
- STACK_SHRINK(2);
- SET_TOP(res);
- if (res == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_TUPLE_1) {
- assert(call_shape.kwnames == NULL);
- assert(oparg == 1);
- DEOPT_IF(is_method(stack_pointer, 1), PRECALL);
- PyObject *callable = PEEK(2);
- DEOPT_IF(callable != (PyObject *)&PyTuple_Type, PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- PyObject *arg = TOP();
- PyObject *res = PySequence_Tuple(arg);
- Py_DECREF(arg);
- Py_DECREF(&PyTuple_Type);
- STACK_SHRINK(2);
- SET_TOP(res);
- if (res == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_BUILTIN_CLASS) {
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- int kwnames_len = KWNAMES_LEN();
- PyObject *callable = PEEK(total_args + 1);
- DEOPT_IF(!PyType_Check(callable), PRECALL);
- PyTypeObject *tp = (PyTypeObject *)callable;
- DEOPT_IF(tp->tp_vectorcall == NULL, PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- STACK_SHRINK(total_args);
- PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer,
- total_args-kwnames_len, call_shape.kwnames);
- call_shape.kwnames = NULL;
- /* Free the arguments. */
- for (int i = 0; i < total_args; i++) {
- Py_DECREF(stack_pointer[i]);
- }
- Py_DECREF(tp);
- STACK_SHRINK(1-is_meth);
- SET_TOP(res);
- if (res == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_BUILTIN_O) {
- assert(cframe.use_tracing == 0);
- /* Builtin METH_O functions */
- assert(call_shape.kwnames == NULL);
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- DEOPT_IF(total_args != 1, PRECALL);
- PyObject *callable = PEEK(total_args + 1);
- DEOPT_IF(!PyCFunction_CheckExact(callable), PRECALL);
- DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
- // This is slower but CPython promises to check all non-vectorcall
- // function calls.
- if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) {
- goto error;
- }
- PyObject *arg = TOP();
- PyObject *res = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable), arg);
- _Py_LeaveRecursiveCallTstate(tstate);
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
-
- Py_DECREF(arg);
- Py_DECREF(callable);
- STACK_SHRINK(2-is_meth);
- SET_TOP(res);
- if (res == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_BUILTIN_FAST) {
- assert(cframe.use_tracing == 0);
- /* Builtin METH_FASTCALL functions, without keywords */
- assert(call_shape.kwnames == NULL);
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- PyObject *callable = PEEK(total_args + 1);
- DEOPT_IF(!PyCFunction_CheckExact(callable), PRECALL);
- DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL,
- PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
- STACK_SHRINK(total_args);
- /* res = func(self, args, nargs) */
- PyObject *res = ((_PyCFunctionFast)(void(*)(void))cfunc)(
- PyCFunction_GET_SELF(callable),
- stack_pointer,
- total_args);
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
-
- /* Free the arguments. */
- for (int i = 0; i < total_args; i++) {
- Py_DECREF(stack_pointer[i]);
- }
- STACK_SHRINK(2-is_meth);
- PUSH(res);
- Py_DECREF(callable);
- if (res == NULL) {
- /* Not deopting because this doesn't mean our optimization was
- wrong. `res` can be NULL for valid reasons. Eg. getattr(x,
- 'invalid'). In those cases an exception is set, so we must
- handle it.
- */
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_BUILTIN_FAST_WITH_KEYWORDS) {
- assert(cframe.use_tracing == 0);
- /* Builtin METH_FASTCALL | METH_KEYWORDS functions */
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- PyObject *callable = PEEK(total_args + 1);
- DEOPT_IF(!PyCFunction_CheckExact(callable), PRECALL);
- DEOPT_IF(PyCFunction_GET_FLAGS(callable) !=
- (METH_FASTCALL | METH_KEYWORDS), PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- STACK_SHRINK(total_args);
- /* res = func(self, args, nargs, kwnames) */
- _PyCFunctionFastWithKeywords cfunc =
- (_PyCFunctionFastWithKeywords)(void(*)(void))
- PyCFunction_GET_FUNCTION(callable);
- PyObject *res = cfunc(
- PyCFunction_GET_SELF(callable),
- stack_pointer,
- total_args - KWNAMES_LEN(),
- call_shape.kwnames
- );
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
- call_shape.kwnames = NULL;
-
- /* Free the arguments. */
- for (int i = 0; i < total_args; i++) {
- Py_DECREF(stack_pointer[i]);
- }
- STACK_SHRINK(2-is_meth);
- PUSH(res);
- Py_DECREF(callable);
- if (res == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_LEN) {
- assert(cframe.use_tracing == 0);
- assert(call_shape.kwnames == NULL);
- /* len(o) */
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- DEOPT_IF(total_args != 1, PRECALL);
- PyObject *callable = PEEK(total_args + 1);
- PyInterpreterState *interp = _PyInterpreterState_GET();
- DEOPT_IF(callable != interp->callable_cache.len, PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- PyObject *arg = TOP();
- Py_ssize_t len_i = PyObject_Length(arg);
- if (len_i < 0) {
- goto error;
- }
- PyObject *res = PyLong_FromSsize_t(len_i);
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
-
- STACK_SHRINK(2-is_meth);
- SET_TOP(res);
- Py_DECREF(callable);
- Py_DECREF(arg);
- if (res == NULL) {
- goto error;
- }
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_ISINSTANCE) {
- assert(cframe.use_tracing == 0);
- assert(call_shape.kwnames == NULL);
- /* isinstance(o, o2) */
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- PyObject *callable = PEEK(total_args + 1);
- DEOPT_IF(total_args != 2, PRECALL);
- PyInterpreterState *interp = _PyInterpreterState_GET();
- DEOPT_IF(callable != interp->callable_cache.isinstance, PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- PyObject *cls = POP();
- PyObject *inst = TOP();
- int retval = PyObject_IsInstance(inst, cls);
- if (retval < 0) {
- Py_DECREF(cls);
- goto error;
- }
- PyObject *res = PyBool_FromLong(retval);
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
-
- STACK_SHRINK(2-is_meth);
- SET_TOP(res);
- Py_DECREF(inst);
- Py_DECREF(cls);
- Py_DECREF(callable);
- if (res == NULL) {
- goto error;
- }
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_LIST_APPEND) {
- assert(cframe.use_tracing == 0);
- assert(call_shape.kwnames == NULL);
- assert(oparg == 1);
- PyObject *callable = PEEK(3);
- PyInterpreterState *interp = _PyInterpreterState_GET();
- DEOPT_IF(callable != interp->callable_cache.list_append, PRECALL);
- PyObject *list = SECOND();
- DEOPT_IF(!PyList_Check(list), PRECALL);
- STAT_INC(PRECALL, hit);
- PyObject *arg = POP();
- if (_PyList_AppendTakeRef((PyListObject *)list, arg) < 0) {
- goto error;
- }
- STACK_SHRINK(2);
- Py_DECREF(list);
- Py_DECREF(callable);
- // PRECALL + CALL + POP_TOP
- JUMPBY(INLINE_CACHE_ENTRIES_PRECALL + 1 + INLINE_CACHE_ENTRIES_CALL + 1);
- assert(_Py_OPCODE(next_instr[-1]) == POP_TOP);
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_O) {
- assert(call_shape.kwnames == NULL);
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
- DEOPT_IF(total_args != 2, PRECALL);
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL);
- PyMethodDef *meth = callable->d_method;
- DEOPT_IF(meth->ml_flags != METH_O, PRECALL);
- PyObject *arg = TOP();
- PyObject *self = SECOND();
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- PyCFunction cfunc = meth->ml_meth;
- // This is slower but CPython promises to check all non-vectorcall
- // function calls.
- if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) {
- goto error;
- }
- PyObject *res = _PyCFunction_TrampolineCall(cfunc, self, arg);
- _Py_LeaveRecursiveCallTstate(tstate);
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
- Py_DECREF(self);
- Py_DECREF(arg);
- STACK_SHRINK(oparg + 1);
- SET_TOP(res);
- Py_DECREF(callable);
- if (res == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS) {
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL);
- PyMethodDef *meth = callable->d_method;
- DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), PRECALL);
- PyTypeObject *d_type = callable->d_common.d_type;
- PyObject *self = PEEK(total_args);
- DEOPT_IF(!Py_IS_TYPE(self, d_type), PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- int nargs = total_args-1;
- STACK_SHRINK(nargs);
- _PyCFunctionFastWithKeywords cfunc =
- (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth;
- PyObject *res = cfunc(self, stack_pointer, nargs - KWNAMES_LEN(),
- call_shape.kwnames);
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
- call_shape.kwnames = NULL;
-
- /* Free the arguments. */
- for (int i = 0; i < nargs; i++) {
- Py_DECREF(stack_pointer[i]);
- }
- Py_DECREF(self);
- STACK_SHRINK(2-is_meth);
- SET_TOP(res);
- Py_DECREF(callable);
- if (res == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) {
- assert(call_shape.kwnames == NULL);
- assert(oparg == 0 || oparg == 1);
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- DEOPT_IF(total_args != 1, PRECALL);
- PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND();
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL);
- PyMethodDef *meth = callable->d_method;
- PyObject *self = TOP();
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), PRECALL);
- DEOPT_IF(meth->ml_flags != METH_NOARGS, PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- PyCFunction cfunc = meth->ml_meth;
- // This is slower but CPython promises to check all non-vectorcall
- // function calls.
- if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) {
- goto error;
- }
- PyObject *res = _PyCFunction_TrampolineCall(cfunc, self, NULL);
- _Py_LeaveRecursiveCallTstate(tstate);
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
- Py_DECREF(self);
- STACK_SHRINK(oparg + 1);
- SET_TOP(res);
- Py_DECREF(callable);
- if (res == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(PRECALL_NO_KW_METHOD_DESCRIPTOR_FAST) {
- assert(call_shape.kwnames == NULL);
- int is_meth = is_method(stack_pointer, oparg);
- int total_args = oparg + is_meth;
- PyMethodDescrObject *callable =
- (PyMethodDescrObject *)PEEK(total_args + 1);
- /* Builtin METH_FASTCALL methods, without keywords */
- DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), PRECALL);
- PyMethodDef *meth = callable->d_method;
- DEOPT_IF(meth->ml_flags != METH_FASTCALL, PRECALL);
- PyObject *self = PEEK(total_args);
- DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), PRECALL);
- STAT_INC(PRECALL, hit);
- SKIP_CALL();
- _PyCFunctionFast cfunc =
- (_PyCFunctionFast)(void(*)(void))meth->ml_meth;
- int nargs = total_args-1;
- STACK_SHRINK(nargs);
- PyObject *res = cfunc(self, stack_pointer, nargs);
- assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
- /* Clear the stack of the arguments. */
- for (int i = 0; i < nargs; i++) {
- Py_DECREF(stack_pointer[i]);
- }
- Py_DECREF(self);
- STACK_SHRINK(2-is_meth);
- SET_TOP(res);
- Py_DECREF(callable);
- if (res == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(CALL_FUNCTION_EX) {
- PREDICTED(CALL_FUNCTION_EX);
- PyObject *func, *callargs, *kwargs = NULL, *result;
- if (oparg & 0x01) {
- kwargs = POP();
- if (!PyDict_CheckExact(kwargs)) {
- PyObject *d = PyDict_New();
- if (d == NULL)
- goto error;
- if (_PyDict_MergeEx(d, kwargs, 2) < 0) {
- Py_DECREF(d);
- format_kwargs_error(tstate, SECOND(), kwargs);
- Py_DECREF(kwargs);
- goto error;
- }
- Py_DECREF(kwargs);
- kwargs = d;
- }
- assert(PyDict_CheckExact(kwargs));
- }
- callargs = POP();
- func = TOP();
- if (!PyTuple_CheckExact(callargs)) {
- if (check_args_iterable(tstate, func, callargs) < 0) {
- Py_DECREF(callargs);
- goto error;
- }
- Py_SETREF(callargs, PySequence_Tuple(callargs));
- if (callargs == NULL) {
- goto error;
- }
- }
- assert(PyTuple_CheckExact(callargs));
-
- result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing);
- Py_DECREF(func);
- Py_DECREF(callargs);
- Py_XDECREF(kwargs);
-
- STACK_SHRINK(1);
- assert(TOP() == NULL);
- SET_TOP(result);
- if (result == NULL) {
- goto error;
- }
- CHECK_EVAL_BREAKER();
- DISPATCH();
- }
-
- TARGET(MAKE_FUNCTION) {
- PyObject *codeobj = POP();
- PyFunctionObject *func = (PyFunctionObject *)
- PyFunction_New(codeobj, GLOBALS());
-
- Py_DECREF(codeobj);
- if (func == NULL) {
- goto error;
- }
-
- if (oparg & 0x08) {
- assert(PyTuple_CheckExact(TOP()));
- func->func_closure = POP();
- }
- if (oparg & 0x04) {
- assert(PyTuple_CheckExact(TOP()));
- func->func_annotations = POP();
- }
- if (oparg & 0x02) {
- assert(PyDict_CheckExact(TOP()));
- func->func_kwdefaults = POP();
- }
- if (oparg & 0x01) {
- assert(PyTuple_CheckExact(TOP()));
- func->func_defaults = POP();
- }
-
- PUSH((PyObject *)func);
- DISPATCH();
- }
-
- TARGET(RETURN_GENERATOR) {
- PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(frame->f_func);
- if (gen == NULL) {
- goto error;
- }
- assert(EMPTY());
- _PyFrame_SetStackPointer(frame, stack_pointer);
- _PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- _PyFrame_Copy(frame, gen_frame);
- assert(frame->frame_obj == NULL);
- gen->gi_frame_state = FRAME_CREATED;
- gen_frame->owner = FRAME_OWNED_BY_GENERATOR;
- _Py_LeaveRecursiveCallTstate(tstate);
- if (!frame->is_entry) {
- _PyInterpreterFrame *prev = frame->previous;
- _PyThreadState_PopFrame(tstate, frame);
- frame = cframe.current_frame = prev;
- _PyFrame_StackPush(frame, (PyObject *)gen);
- goto resume_frame;
- }
- /* Make sure that frame is in a valid state */
- frame->stacktop = 0;
- frame->f_locals = NULL;
- Py_INCREF(frame->f_func);
- Py_INCREF(frame->f_code);
- /* Restore previous cframe and return. */
- tstate->cframe = cframe.previous;
- tstate->cframe->use_tracing = cframe.use_tracing;
- assert(tstate->cframe->current_frame == frame->previous);
- assert(!_PyErr_Occurred(tstate));
- return (PyObject *)gen;
- }
-
- TARGET(BUILD_SLICE) {
- PyObject *start, *stop, *step, *slice;
- if (oparg == 3)
- step = POP();
- else
- step = NULL;
- stop = POP();
- start = TOP();
- slice = PySlice_New(start, stop, step);
- Py_DECREF(start);
- Py_DECREF(stop);
- Py_XDECREF(step);
- SET_TOP(slice);
- if (slice == NULL)
- goto error;
- DISPATCH();
- }
-
- TARGET(FORMAT_VALUE) {
- /* Handles f-string value formatting. */
- PyObject *result;
- PyObject *fmt_spec;
- PyObject *value;
- PyObject *(*conv_fn)(PyObject *);
- int which_conversion = oparg & FVC_MASK;
- int have_fmt_spec = (oparg & FVS_MASK) == FVS_HAVE_SPEC;
-
- fmt_spec = have_fmt_spec ? POP() : NULL;
- value = POP();
-
- /* See if any conversion is specified. */
- switch (which_conversion) {
- case FVC_NONE: conv_fn = NULL; break;
- case FVC_STR: conv_fn = PyObject_Str; break;
- case FVC_REPR: conv_fn = PyObject_Repr; break;
- case FVC_ASCII: conv_fn = PyObject_ASCII; break;
- default:
- _PyErr_Format(tstate, PyExc_SystemError,
- "unexpected conversion flag %d",
- which_conversion);
- goto error;
- }
-
- /* If there's a conversion function, call it and replace
- value with that result. Otherwise, just use value,
- without conversion. */
- if (conv_fn != NULL) {
- result = conv_fn(value);
- Py_DECREF(value);
- if (result == NULL) {
- Py_XDECREF(fmt_spec);
- goto error;
- }
- value = result;
- }
-
- /* If value is a unicode object, and there's no fmt_spec,
- then we know the result of format(value) is value
- itself. In that case, skip calling format(). I plan to
- move this optimization in to PyObject_Format()
- itself. */
- if (PyUnicode_CheckExact(value) && fmt_spec == NULL) {
- /* Do nothing, just transfer ownership to result. */
- result = value;
- } else {
- /* Actually call format(). */
- result = PyObject_Format(value, fmt_spec);
- Py_DECREF(value);
- Py_XDECREF(fmt_spec);
- if (result == NULL) {
- goto error;
- }
- }
-
- PUSH(result);
- DISPATCH();
- }
-
- TARGET(COPY) {
- assert(oparg != 0);
- PyObject *peek = PEEK(oparg);
- Py_INCREF(peek);
- PUSH(peek);
- DISPATCH();
- }
-
- TARGET(BINARY_OP) {
- PREDICTED(BINARY_OP);
- PyObject *rhs = POP();
- PyObject *lhs = TOP();
- assert(0 <= oparg);
- assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops));
- assert(binary_ops[oparg]);
- PyObject *res = binary_ops[oparg](lhs, rhs);
- Py_DECREF(lhs);
- Py_DECREF(rhs);
- SET_TOP(res);
- if (res == NULL) {
- goto error;
- }
- JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP);
- DISPATCH();
- }
-
- TARGET(BINARY_OP_ADAPTIVE) {
- assert(cframe.use_tracing == 0);
- _PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr;
- if (ADAPTIVE_COUNTER_IS_ZERO(cache)) {
- PyObject *lhs = SECOND();
- PyObject *rhs = TOP();
- next_instr--;
- _Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0));
- DISPATCH_SAME_OPARG();
- }
- else {
- STAT_INC(BINARY_OP, deferred);
- DECREMENT_ADAPTIVE_COUNTER(cache);
- JUMP_TO_INSTRUCTION(BINARY_OP);
- }
- }
-
- TARGET(SWAP) {
- assert(oparg != 0);
- PyObject *top = TOP();
- SET_TOP(PEEK(oparg));
- PEEK(oparg) = top;
- DISPATCH();
- }
-
- TARGET(EXTENDED_ARG) {
- assert(oparg);
- oparg <<= 8;
- oparg |= _Py_OPARG(*next_instr);
- // We might be tracing. To avoid breaking tracing guarantees in
- // quickened instructions, always deoptimize the next opcode:
- opcode = _PyOpcode_Deopt[_Py_OPCODE(*next_instr)];
- PRE_DISPATCH_GOTO();
- // CPython hasn't traced the following instruction historically
- // (DO_TRACING would clobber our extended oparg anyways), so just
- // skip our usual cframe.use_tracing check before dispatch. Also,
- // make sure the next instruction isn't a RESUME, since that needs
- // to trace properly (and shouldn't have an extended arg anyways):
- assert(opcode != RESUME);
- DISPATCH_GOTO();
- }
-
- TARGET(EXTENDED_ARG_QUICK) {
- assert(cframe.use_tracing == 0);
- assert(oparg);
- int oldoparg = oparg;
- NEXTOPARG();
- oparg |= oldoparg << 8;
- DISPATCH_GOTO();
- }
+ {
- TARGET(CACHE) {
- Py_UNREACHABLE();
- }
+#include "generated_cases.c.h"
+ /* INSTRUMENTED_LINE has to be here, rather than in bytecodes.c,
+ * because it needs to capture frame->prev_instr before it is updated,
+ * as happens in the standard instruction prologue.
+ */
#if USE_COMPUTED_GOTOS
- TARGET_DO_TRACING:
+ TARGET_INSTRUMENTED_LINE:
#else
- case DO_TRACING:
+ case INSTRUMENTED_LINE:
#endif
{
- assert(cframe.use_tracing);
- assert(tstate->tracing == 0);
- if (INSTR_OFFSET() >= frame->f_code->_co_firsttraceable) {
- int instr_prev = _PyInterpreterFrame_LASTI(frame);
- frame->prev_instr = next_instr;
- TRACING_NEXTOPARG();
- if (opcode == RESUME) {
- if (oparg < 2) {
- CHECK_EVAL_BREAKER();
- }
- /* 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);
- }
-
- if (cframe.use_tracing &&
- tstate->c_tracefunc != NULL && !tstate->tracing) {
- int err;
- /* see maybe_call_line_trace()
- for expository comments */
- _PyFrame_SetStackPointer(frame, stack_pointer);
-
- err = maybe_call_line_trace(tstate->c_tracefunc,
- tstate->c_traceobj,
- tstate, frame, instr_prev);
- // Reload possibly changed frame fields:
- stack_pointer = _PyFrame_GetStackPointer(frame);
- frame->stacktop = -1;
- // next_instr is only reloaded if tracing *does not* raise.
- // This is consistent with the behavior of older Python
- // versions. If a trace function sets a new f_lineno and
- // *then* raises, we use the *old* location when searching
- // for an exception handler, displaying the traceback, and
- // so on:
- if (err) {
- // next_instr wasn't incremented at the start of this
- // instruction. Increment it before handling the error,
- // so that it looks the same as a "normal" instruction:
- next_instr++;
- goto error;
- }
- // Reload next_instr. Don't increment it, though, since
- // we're going to re-dispatch to the "true" instruction now:
- next_instr = frame->prev_instr;
- }
- }
+ _Py_CODEUNIT *prev = frame->prev_instr;
+ _Py_CODEUNIT *here = frame->prev_instr = next_instr;
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ int original_opcode = _Py_call_instrumentation_line(
+ tstate, frame, here, prev);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ if (original_opcode < 0) {
+ next_instr = here+1;
+ goto error;
+ }
+ next_instr = frame->prev_instr;
+ if (next_instr != here) {
+ DISPATCH();
+ }
+ if (_PyOpcode_Caches[original_opcode]) {
+ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1);
+ /* Prevent the underlying instruction from specializing
+ * and overwriting the instrumentation. */
+ INCREMENT_ADAPTIVE_COUNTER(cache->counter);
}
- TRACING_NEXTOPARG();
- PRE_DISPATCH_GOTO();
+ opcode = original_opcode;
DISPATCH_GOTO();
}
+
#if USE_COMPUTED_GOTOS
_unknown_opcode:
#else
@@ -5681,10 +888,12 @@ handle_eval_breaker:
#endif
/* Tell C compilers not to hold the opcode variable in the loop.
next_instr points the current instruction without TARGET(). */
- opcode = _Py_OPCODE(*next_instr);
- fprintf(stderr, "XXX lineno: %d, opcode: %d\n",
- _PyInterpreterFrame_GetLine(frame), opcode);
- _PyErr_SetString(tstate, PyExc_SystemError, "unknown opcode");
+ opcode = next_instr->op.code;
+ _PyErr_Format(tstate, PyExc_SystemError,
+ "%U:%d: unknown opcode %d",
+ frame->f_code->co_filename,
+ PyUnstable_InterpreterFrame_GetLine(frame),
+ opcode);
goto error;
} /* End instructions */
@@ -5693,37 +902,6 @@ handle_eval_breaker:
or goto error. */
Py_UNREACHABLE();
-/* Specialization misses */
-
-miss:
- {
- STAT_INC(opcode, miss);
- opcode = _PyOpcode_Deopt[opcode];
- STAT_INC(opcode, miss);
- /* The counter is always the first cache entry: */
- _Py_CODEUNIT *counter = (_Py_CODEUNIT *)next_instr;
- *counter -= 1;
- if (*counter == 0) {
- int adaptive_opcode = _PyOpcode_Adaptive[opcode];
- assert(adaptive_opcode);
- _Py_SET_OPCODE(next_instr[-1], adaptive_opcode);
- STAT_INC(opcode, deopt);
- *counter = adaptive_counter_start();
- }
- next_instr--;
- DISPATCH_GOTO();
- }
-
-binary_subscr_dict_error:
- {
- PyObject *sub = POP();
- if (!_PyErr_Occurred(tstate)) {
- _PyErr_SetKeyError(sub);
- }
- Py_DECREF(sub);
- goto error;
- }
-
unbound_local_error:
{
format_exc_check_arg(tstate, PyExc_UnboundLocalError,
@@ -5733,8 +911,16 @@ unbound_local_error:
goto error;
}
+pop_4_error:
+ STACK_SHRINK(1);
+pop_3_error:
+ STACK_SHRINK(1);
+pop_2_error:
+ STACK_SHRINK(1);
+pop_1_error:
+ STACK_SHRINK(1);
error:
- call_shape.kwnames = NULL;
+ kwnames = NULL;
/* Double-check exception status. */
#ifdef NDEBUG
if (!_PyErr_Occurred(tstate)) {
@@ -5746,19 +932,14 @@ error:
#endif
/* Log traceback info. */
+ assert(frame != &entry_frame);
if (!_PyFrame_IsIncomplete(frame)) {
PyFrameObject *f = _PyFrame_GetFrameObject(frame);
if (f != NULL) {
PyTraceBack_Here(f);
}
}
-
- if (tstate->c_tracefunc != NULL) {
- /* Make sure state is set to FRAME_UNWINDING for tracing */
- call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj,
- tstate, frame);
- }
-
+ monitor_raise(tstate, frame, next_instr-1);
exception_unwind:
{
/* We can't use frame->f_lasti here, as RERAISE may have set it */
@@ -5776,8 +957,7 @@ exception_unwind:
}
assert(STACK_LEVEL() == 0);
_PyFrame_SetStackPointer(frame, stack_pointer);
- TRACE_FUNCTION_UNWIND();
- DTRACE_FUNCTION_EXIT();
+ monitor_unwind(tstate, frame, next_instr-1);
goto exit_unwind;
}
@@ -5787,7 +967,6 @@ exception_unwind:
PyObject *v = POP();
Py_XDECREF(v);
}
- PyObject *exc, *val, *tb;
if (lasti) {
int frame_lasti = _PyInterpreterFrame_LASTI(frame);
PyObject *lasti = PyLong_FromLong(frame_lasti);
@@ -5796,20 +975,17 @@ exception_unwind:
}
PUSH(lasti);
}
- _PyErr_Fetch(tstate, &exc, &val, &tb);
+
/* Make the raw exception data
available to the handler,
so a program can emulate the
Python main loop. */
- _PyErr_NormalizeException(tstate, &exc, &val, &tb);
- if (tb != NULL)
- PyException_SetTraceback(val, tb);
- else
- PyException_SetTraceback(val, Py_None);
- Py_XDECREF(tb);
- Py_XDECREF(exc);
- PUSH(val);
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ PUSH(exc);
JUMPTO(handler);
+ if (monitor_handled(tstate, frame, next_instr, exc) < 0) {
+ goto exception_unwind;
+ }
/* Resume normal execution */
DISPATCH();
}
@@ -5817,24 +993,31 @@ exception_unwind:
exit_unwind:
assert(_PyErr_Occurred(tstate));
- _Py_LeaveRecursiveCallTstate(tstate);
- if (frame->is_entry) {
+ _Py_LeaveRecursiveCallPy(tstate);
+ assert(frame != &entry_frame);
+ // GH-99729: We need to unlink the frame *before* clearing it:
+ _PyInterpreterFrame *dying = frame;
+ frame = cframe.current_frame = dying->previous;
+ _PyEvalFrameClearAndPop(tstate, dying);
+ frame->return_offset = 0;
+ if (frame == &entry_frame) {
/* Restore previous cframe and exit */
tstate->cframe = cframe.previous;
- tstate->cframe->use_tracing = cframe.use_tracing;
assert(tstate->cframe->current_frame == frame->previous);
+ tstate->c_recursion_remaining += PY_EVAL_C_STACK_UNITS;
return NULL;
}
- // GH-99729: We need to unlink the frame *before* clearing it:
- _PyInterpreterFrame *dying = frame;
- frame = cframe.current_frame = dying->previous;
- _PyEvalFrameClearAndPop(tstate, dying);
resume_with_error:
SET_LOCALS_FROM_FRAME();
goto error;
}
+#if defined(__GNUC__)
+# pragma GCC diagnostic pop
+#elif defined(_MSC_VER) /* MS_WINDOWS */
+# pragma warning(pop)
+#endif
static void
format_missing(PyThreadState *tstate, const char *kind,
@@ -6302,8 +1485,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
for (; i < defcount; i++) {
if (localsplus[m+i] == NULL) {
PyObject *def = defs[i];
- Py_INCREF(def);
- localsplus[m+i] = def;
+ localsplus[m+i] = Py_NewRef(def);
}
}
}
@@ -6319,8 +1501,7 @@ initialize_locals(PyThreadState *tstate, PyFunctionObject *func,
if (func->func_kwdefaults != NULL) {
PyObject *def = PyDict_GetItemWithError(func->func_kwdefaults, varname);
if (def) {
- Py_INCREF(def);
- localsplus[i] = def;
+ localsplus[i] = Py_NewRef(def);
continue;
}
else if (_PyErr_Occurred(tstate)) {
@@ -6354,27 +1535,65 @@ fail_post_args:
return -1;
}
-/* Consumes references to func and all the args */
+static void
+clear_thread_frame(PyThreadState *tstate, _PyInterpreterFrame * frame)
+{
+ assert(frame->owner == FRAME_OWNED_BY_THREAD);
+ // Make sure that this is, indeed, the top frame. We can't check this in
+ // _PyThreadState_PopFrame, since f_code is already cleared at that point:
+ assert((PyObject **)frame + frame->f_code->co_framesize ==
+ tstate->datastack_top);
+ tstate->c_recursion_remaining--;
+ assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
+ _PyFrame_ClearExceptCode(frame);
+ Py_DECREF(frame->f_code);
+ tstate->c_recursion_remaining++;
+ _PyThreadState_PopFrame(tstate, frame);
+}
+
+static void
+clear_gen_frame(PyThreadState *tstate, _PyInterpreterFrame * frame)
+{
+ assert(frame->owner == FRAME_OWNED_BY_GENERATOR);
+ PyGenObject *gen = _PyFrame_GetGenerator(frame);
+ gen->gi_frame_state = FRAME_CLEARED;
+ assert(tstate->exc_info == &gen->gi_exc_state);
+ tstate->exc_info = gen->gi_exc_state.previous_item;
+ gen->gi_exc_state.previous_item = NULL;
+ tstate->c_recursion_remaining--;
+ assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
+ _PyFrame_ClearExceptCode(frame);
+ tstate->c_recursion_remaining++;
+ frame->previous = NULL;
+}
+
+static void
+_PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame)
+{
+ if (frame->owner == FRAME_OWNED_BY_THREAD) {
+ clear_thread_frame(tstate, frame);
+ }
+ else {
+ clear_gen_frame(tstate, frame);
+ }
+}
+
+/* Consumes references to func, locals and all the args */
static _PyInterpreterFrame *
_PyEvalFramePushAndInit(PyThreadState *tstate, PyFunctionObject *func,
PyObject *locals, PyObject* const* args,
size_t argcount, PyObject *kwnames)
{
PyCodeObject * code = (PyCodeObject *)func->func_code;
- size_t size = code->co_nlocalsplus + code->co_stacksize + FRAME_SPECIALS_SIZE;
CALL_STAT_INC(frames_pushed);
- _PyInterpreterFrame *frame = _PyThreadState_BumpFramePointer(tstate, size);
+ _PyInterpreterFrame *frame = _PyThreadState_PushFrame(tstate, code->co_framesize);
if (frame == NULL) {
goto fail;
}
- _PyFrame_InitializeSpecials(frame, func, locals, code->co_nlocalsplus);
- PyObject **localsarray = &frame->localsplus[0];
- for (int i = 0; i < code->co_nlocalsplus; i++) {
- localsarray[i] = NULL;
- }
- if (initialize_locals(tstate, func, localsarray, args, argcount, kwnames)) {
- assert(frame->owner != FRAME_OWNED_BY_GENERATOR);
- _PyEvalFrameClearAndPop(tstate, frame);
+ _PyFrame_Initialize(frame, func, locals, code, 0);
+ if (initialize_locals(tstate, func, frame->localsplus, args, argcount, kwnames)) {
+ assert(frame->owner == FRAME_OWNED_BY_THREAD);
+ clear_thread_frame(tstate, frame);
return NULL;
}
return frame;
@@ -6393,19 +1612,47 @@ fail:
return NULL;
}
-static void
-_PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame * frame)
+/* Same as _PyEvalFramePushAndInit but takes an args tuple and kwargs dict.
+ Steals references to func, callargs and kwargs.
+*/
+static _PyInterpreterFrame *
+_PyEvalFramePushAndInit_Ex(PyThreadState *tstate, PyFunctionObject *func,
+ PyObject *locals, Py_ssize_t nargs, PyObject *callargs, PyObject *kwargs)
{
- // Make sure that this is, indeed, the top frame. We can't check this in
- // _PyThreadState_PopFrame, since f_code is already cleared at that point:
- assert((PyObject **)frame + frame->f_code->co_nlocalsplus +
- frame->f_code->co_stacksize + FRAME_SPECIALS_SIZE == tstate->datastack_top);
- tstate->recursion_remaining--;
- assert(frame->frame_obj == NULL || frame->frame_obj->f_frame == frame);
- assert(frame->owner == FRAME_OWNED_BY_THREAD);
- _PyFrame_Clear(frame);
- tstate->recursion_remaining++;
- _PyThreadState_PopFrame(tstate, frame);
+ bool has_dict = (kwargs != NULL && PyDict_GET_SIZE(kwargs) > 0);
+ PyObject *kwnames = NULL;
+ PyObject *const *newargs;
+ if (has_dict) {
+ newargs = _PyStack_UnpackDict(tstate, _PyTuple_ITEMS(callargs), nargs, kwargs, &kwnames);
+ if (newargs == NULL) {
+ Py_DECREF(func);
+ goto error;
+ }
+ }
+ else {
+ newargs = &PyTuple_GET_ITEM(callargs, 0);
+ /* We need to incref all our args since the new frame steals the references. */
+ for (Py_ssize_t i = 0; i < nargs; ++i) {
+ Py_INCREF(PyTuple_GET_ITEM(callargs, i));
+ }
+ }
+ _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit(
+ tstate, (PyFunctionObject *)func, locals,
+ newargs, nargs, kwnames
+ );
+ if (has_dict) {
+ _PyStack_UnpackDict_FreeNoDecRef(newargs, kwnames);
+ }
+ /* No need to decref func here because the reference has been stolen by
+ _PyEvalFramePushAndInit.
+ */
+ Py_DECREF(callargs);
+ Py_XDECREF(kwargs);
+ return new_frame;
+error:
+ Py_DECREF(callargs);
+ Py_XDECREF(kwargs);
+ return NULL;
}
PyObject *
@@ -6415,8 +1662,9 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func,
PyObject *kwnames)
{
/* _PyEvalFramePushAndInit consumes the references
- * to func and all its arguments */
+ * to func, locals and all its arguments */
Py_INCREF(func);
+ Py_XINCREF(locals);
for (size_t i = 0; i < argcount; i++) {
Py_INCREF(args[i]);
}
@@ -6431,13 +1679,8 @@ _PyEval_Vector(PyThreadState *tstate, PyFunctionObject *func,
if (frame == NULL) {
return NULL;
}
- PyObject *retval = _PyEval_EvalFrame(tstate, frame, 0);
- assert(
- _PyFrame_GetStackPointer(frame) == _PyFrame_Stackbase(frame) ||
- _PyFrame_GetStackPointer(frame) == frame->localsplus
- );
- _PyEvalFrameClearAndPop(tstate, frame);
- return retval;
+ EVAL_CALL_STAT_INC(EVAL_CALL_VECTOR);
+ return _PyEval_EvalFrame(tstate, frame, 0);
}
/* Legacy API */
@@ -6482,8 +1725,7 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
newargs[i] = args[i];
}
for (int i = 0; i < kwcount; i++) {
- Py_INCREF(kws[2*i]);
- PyTuple_SET_ITEM(kwnames, i, kws[2*i]);
+ PyTuple_SET_ITEM(kwnames, i, Py_NewRef(kws[2*i]));
newargs[argcount+i] = kws[2*i+1];
}
allargs = newargs;
@@ -6502,6 +1744,7 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
if (func == NULL) {
goto fail;
}
+ EVAL_CALL_STAT_INC(EVAL_CALL_LEGACY);
res = _PyEval_Vector(tstate, func, locals,
allargs, argcount,
kwnames);
@@ -6524,18 +1767,15 @@ do_raise(PyThreadState *tstate, PyObject *exc, PyObject *cause)
if (exc == NULL) {
/* Reraise */
_PyErr_StackItem *exc_info = _PyErr_GetTopmostException(tstate);
- value = exc_info->exc_value;
- if (Py_IsNone(value) || value == NULL) {
+ exc = exc_info->exc_value;
+ if (Py_IsNone(exc) || exc == NULL) {
_PyErr_SetString(tstate, PyExc_RuntimeError,
"No active exception to reraise");
return 0;
}
- assert(PyExceptionInstance_Check(value));
- type = PyExceptionInstance_Class(value);
- Py_XINCREF(type);
- Py_XINCREF(value);
- PyObject *tb = PyException_GetTraceback(value); /* new ref */
- _PyErr_Restore(tstate, type, value, tb);
+ Py_INCREF(exc);
+ assert(PyExceptionInstance_Check(exc));
+ _PyErr_SetRaisedException(tstate, exc);
return 1;
}
@@ -6667,7 +1907,7 @@ exception_group_match(PyObject* exc_value, PyObject *match_type,
}
/* no match */
*match = Py_NewRef(Py_None);
- *rest = Py_NewRef(Py_None);
+ *rest = Py_NewRef(exc_value);
return 0;
}
@@ -6771,111 +2011,121 @@ Error:
return 0;
}
-static void
-call_exc_trace(Py_tracefunc func, PyObject *self,
- PyThreadState *tstate,
- _PyInterpreterFrame *f)
+static int
+do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr, int event)
{
- PyObject *type, *value, *traceback, *orig_traceback, *arg;
- int err;
- _PyErr_Fetch(tstate, &type, &value, &orig_traceback);
- if (value == NULL) {
- value = Py_None;
- Py_INCREF(value);
- }
- _PyErr_NormalizeException(tstate, &type, &value, &orig_traceback);
- traceback = (orig_traceback != NULL) ? orig_traceback : Py_None;
- arg = PyTuple_Pack(3, type, value, traceback);
- if (arg == NULL) {
- _PyErr_Restore(tstate, type, value, orig_traceback);
- return;
- }
- err = call_trace(func, self, tstate, f, PyTrace_EXCEPTION, arg);
- Py_DECREF(arg);
+ assert(event < _PY_MONITORING_UNGROUPED_EVENTS);
+ PyObject *exc = PyErr_GetRaisedException();
+ assert(exc != NULL);
+ int err = _Py_call_instrumentation_arg(tstate, event, frame, instr, exc);
if (err == 0) {
- _PyErr_Restore(tstate, type, value, orig_traceback);
+ PyErr_SetRaisedException(exc);
}
else {
- Py_XDECREF(type);
- Py_XDECREF(value);
- Py_XDECREF(orig_traceback);
+ assert(PyErr_Occurred());
+ Py_DECREF(exc);
+ }
+ return err;
+}
+
+static inline bool
+no_tools_for_global_event(PyThreadState *tstate, int event)
+{
+ return tstate->interp->monitors.tools[event] == 0;
+}
+
+static inline bool
+no_tools_for_local_event(PyThreadState *tstate, _PyInterpreterFrame *frame, int event)
+{
+ assert(event < _PY_MONITORING_LOCAL_EVENTS);
+ _PyCoMonitoringData *data = frame->f_code->_co_monitoring;
+ if (data) {
+ return data->active_monitors.tools[event] == 0;
+ }
+ else {
+ return no_tools_for_global_event(tstate, event);
+ }
+}
+
+static void
+monitor_raise(PyThreadState *tstate, _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr)
+{
+ if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_RAISE)) {
+ return;
+ }
+ do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_RAISE);
+}
+
+static void
+monitor_reraise(PyThreadState *tstate, _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr)
+{
+ if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_RERAISE)) {
+ return;
}
+ do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_RERAISE);
}
static int
-call_trace_protected(Py_tracefunc func, PyObject *obj,
- PyThreadState *tstate, _PyInterpreterFrame *frame,
- int what, PyObject *arg)
+monitor_stop_iteration(PyThreadState *tstate, _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr)
{
- PyObject *type, *value, *traceback;
- int err;
- _PyErr_Fetch(tstate, &type, &value, &traceback);
- err = call_trace(func, obj, tstate, frame, what, arg);
- if (err == 0)
- {
- _PyErr_Restore(tstate, type, value, traceback);
+ if (no_tools_for_local_event(tstate, frame, PY_MONITORING_EVENT_STOP_ITERATION)) {
return 0;
}
- else {
- Py_XDECREF(type);
- Py_XDECREF(value);
- Py_XDECREF(traceback);
- return -1;
+ return do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_STOP_ITERATION);
+}
+
+static void
+monitor_unwind(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr)
+{
+ if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_PY_UNWIND)) {
+ return;
+ }
+ do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_UNWIND);
+}
+
+
+static int
+monitor_handled(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr, PyObject *exc)
+{
+ if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED)) {
+ return 0;
}
+ return _Py_call_instrumentation_arg(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED, frame, instr, exc);
}
static void
-initialize_trace_info(PyTraceInfo *trace_info, _PyInterpreterFrame *frame)
+monitor_throw(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr)
{
- PyCodeObject *code = frame->f_code;
- if (trace_info->code != code) {
- trace_info->code = code;
- _PyCode_InitAddressRange(code, &trace_info->bounds);
+ if (no_tools_for_global_event(tstate, PY_MONITORING_EVENT_PY_THROW)) {
+ return;
}
+ do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_PY_THROW);
}
void
PyThreadState_EnterTracing(PyThreadState *tstate)
{
+ assert(tstate->tracing >= 0);
tstate->tracing++;
- tstate->cframe->use_tracing = 0;
}
void
PyThreadState_LeaveTracing(PyThreadState *tstate)
{
- assert(tstate->tracing > 0 && tstate->cframe->use_tracing == 0);
+ assert(tstate->tracing > 0);
tstate->tracing--;
- _PyThreadState_UpdateTracingState(tstate);
}
-static int
-call_trace(Py_tracefunc func, PyObject *obj,
- PyThreadState *tstate, _PyInterpreterFrame *frame,
- int what, PyObject *arg)
-{
- int result;
- if (tstate->tracing) {
- return 0;
- }
- PyFrameObject *f = _PyFrame_GetFrameObject(frame);
- if (f == NULL) {
- return -1;
- }
- int old_what = tstate->tracing_what;
- tstate->tracing_what = what;
- PyThreadState_EnterTracing(tstate);
- assert(_PyInterpreterFrame_LASTI(frame) >= 0);
- if (_PyCode_InitLineArray(frame->f_code)) {
- return -1;
- }
- f->f_lineno = _PyCode_LineNumberFromArray(frame->f_code, _PyInterpreterFrame_LASTI(frame));
- result = func(obj, f, what, arg);
- f->f_lineno = 0;
- PyThreadState_LeaveTracing(tstate);
- tstate->tracing_what = old_what;
- return result;
-}
PyObject*
_PyEval_CallTracing(PyObject *func, PyObject *args)
@@ -6883,7 +2133,6 @@ _PyEval_CallTracing(PyObject *func, PyObject *args)
// Save and disable tracing
PyThreadState *tstate = _PyThreadState_GET();
int save_tracing = tstate->tracing;
- int save_use_tracing = tstate->cframe->use_tracing;
tstate->tracing = 0;
// Call the tracing function
@@ -6891,96 +2140,9 @@ _PyEval_CallTracing(PyObject *func, PyObject *args)
// Restore tracing
tstate->tracing = save_tracing;
- tstate->cframe->use_tracing = save_use_tracing;
return result;
}
-/* See Objects/lnotab_notes.txt for a description of how tracing works. */
-static int
-maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
- PyThreadState *tstate, _PyInterpreterFrame *frame, int instr_prev)
-{
- int result = 0;
-
- /* If the last instruction falls at the start of a line or if it
- represents a jump backwards, update the frame's line number and
- then call the trace function if we're tracing source lines.
- */
- if (_PyCode_InitLineArray(frame->f_code)) {
- return -1;
- }
- int lastline;
- if (instr_prev <= frame->f_code->_co_firsttraceable) {
- lastline = -1;
- }
- else {
- lastline = _PyCode_LineNumberFromArray(frame->f_code, instr_prev);
- }
- int line = _PyCode_LineNumberFromArray(frame->f_code, _PyInterpreterFrame_LASTI(frame));
- PyFrameObject *f = _PyFrame_GetFrameObject(frame);
- if (f == NULL) {
- return -1;
- }
- if (line != -1 && f->f_trace_lines) {
- /* Trace backward edges (except in 'yield from') or if line number has changed */
- int trace = line != lastline ||
- (_PyInterpreterFrame_LASTI(frame) < instr_prev &&
- // SEND has no quickened forms, so no need to use _PyOpcode_Deopt
- // here:
- _Py_OPCODE(*frame->prev_instr) != SEND);
- if (trace) {
- result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None);
- }
- }
- /* Always emit an opcode event if we're tracing all opcodes. */
- if (f->f_trace_opcodes && result == 0) {
- result = call_trace(func, obj, tstate, frame, PyTrace_OPCODE, Py_None);
- }
- return result;
-}
-
-int
-_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
-{
- assert(_PyThreadState_CheckConsistency(tstate));
- /* The caller must hold the GIL */
- assert(PyGILState_Check());
-
- static int reentrant = 0;
- if (reentrant) {
- _PyErr_SetString(tstate, PyExc_RuntimeError, "Cannot install a profile function "
- "while another profile function is being installed");
- reentrant = 0;
- return -1;
- }
- reentrant = 1;
-
- /* Call _PySys_Audit() in the context of the current thread state,
- even if tstate is not the current thread state. */
- PyThreadState *current_tstate = _PyThreadState_GET();
- if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) {
- reentrant = 0;
- return -1;
- }
-
- PyObject *profileobj = tstate->c_profileobj;
-
- tstate->c_profilefunc = NULL;
- tstate->c_profileobj = NULL;
- /* Must make sure that tracing is not ignored if 'profileobj' is freed */
- _PyThreadState_UpdateTracingState(tstate);
- Py_XDECREF(profileobj);
-
- Py_XINCREF(arg);
- tstate->c_profileobj = arg;
- tstate->c_profilefunc = func;
-
- /* Flag that tracing or profiling is turned on */
- _PyThreadState_UpdateTracingState(tstate);
- reentrant = 0;
- return 0;
-}
-
void
PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
{
@@ -6991,47 +2153,25 @@ PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
}
}
-int
-_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
+void
+PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject *arg)
{
- assert(_PyThreadState_CheckConsistency(tstate));
- /* The caller must hold the GIL */
- assert(PyGILState_Check());
-
- static int reentrant = 0;
+ PyThreadState *this_tstate = _PyThreadState_GET();
+ PyInterpreterState* interp = this_tstate->interp;
- if (reentrant) {
- _PyErr_SetString(tstate, PyExc_RuntimeError, "Cannot install a trace function "
- "while another trace function is being installed");
- reentrant = 0;
- return -1;
- }
- reentrant = 1;
+ _PyRuntimeState *runtime = &_PyRuntime;
+ HEAD_LOCK(runtime);
+ PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
+ HEAD_UNLOCK(runtime);
- /* Call _PySys_Audit() in the context of the current thread state,
- even if tstate is not the current thread state. */
- PyThreadState *current_tstate = _PyThreadState_GET();
- if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) {
- reentrant = 0;
- return -1;
+ while (ts) {
+ if (_PyEval_SetProfile(ts, func, arg) < 0) {
+ _PyErr_WriteUnraisableMsg("in PyEval_SetProfileAllThreads", NULL);
+ }
+ HEAD_LOCK(runtime);
+ ts = PyThreadState_Next(ts);
+ HEAD_UNLOCK(runtime);
}
-
- PyObject *traceobj = tstate->c_traceobj;
-
- tstate->c_tracefunc = NULL;
- tstate->c_traceobj = NULL;
- /* Must make sure that profiling is not ignored if 'traceobj' is freed */
- _PyThreadState_UpdateTracingState(tstate);
- Py_XINCREF(arg);
- Py_XDECREF(traceobj);
- tstate->c_traceobj = arg;
- tstate->c_tracefunc = func;
-
- /* Flag that tracing or profiling is turned on */
- _PyThreadState_UpdateTracingState(tstate);
-
- reentrant = 0;
- return 0;
}
void
@@ -7044,6 +2184,26 @@ PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
}
}
+void
+PyEval_SetTraceAllThreads(Py_tracefunc func, PyObject *arg)
+{
+ PyThreadState *this_tstate = _PyThreadState_GET();
+ PyInterpreterState* interp = this_tstate->interp;
+
+ _PyRuntimeState *runtime = &_PyRuntime;
+ HEAD_LOCK(runtime);
+ PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
+ HEAD_UNLOCK(runtime);
+
+ while (ts) {
+ if (_PyEval_SetTrace(ts, func, arg) < 0) {
+ _PyErr_WriteUnraisableMsg("in PyEval_SetTraceAllThreads", NULL);
+ }
+ HEAD_LOCK(runtime);
+ ts = PyThreadState_Next(ts);
+ HEAD_UNLOCK(runtime);
+ }
+}
int
_PyEval_SetCoroutineOriginTrackingDepth(int depth)
@@ -7074,8 +2234,7 @@ _PyEval_SetAsyncGenFirstiter(PyObject *firstiter)
return -1;
}
- Py_XINCREF(firstiter);
- Py_XSETREF(tstate->async_gen_firstiter, firstiter);
+ Py_XSETREF(tstate->async_gen_firstiter, Py_XNewRef(firstiter));
return 0;
}
@@ -7095,8 +2254,7 @@ _PyEval_SetAsyncGenFinalizer(PyObject *finalizer)
return -1;
}
- Py_XINCREF(finalizer);
- Py_XSETREF(tstate->async_gen_finalizer, finalizer);
+ Py_XSETREF(tstate->async_gen_finalizer, Py_XNewRef(finalizer));
return 0;
}
@@ -7111,16 +2269,13 @@ _PyInterpreterFrame *
_PyEval_GetFrame(void)
{
PyThreadState *tstate = _PyThreadState_GET();
- return tstate->cframe->current_frame;
+ return _PyThreadState_GetFrame(tstate);
}
PyFrameObject *
PyEval_GetFrame(void)
{
_PyInterpreterFrame *frame = _PyEval_GetFrame();
- while (frame && _PyFrame_IsIncomplete(frame)) {
- frame = frame->previous;
- }
if (frame == NULL) {
return NULL;
}
@@ -7134,7 +2289,7 @@ PyEval_GetFrame(void)
PyObject *
_PyEval_GetBuiltins(PyThreadState *tstate)
{
- _PyInterpreterFrame *frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *frame = _PyThreadState_GetFrame(tstate);
if (frame != NULL) {
return frame->f_builtins;
}
@@ -7170,7 +2325,7 @@ PyObject *
PyEval_GetLocals(void)
{
PyThreadState *tstate = _PyThreadState_GET();
- _PyInterpreterFrame *current_frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate);
if (current_frame == NULL) {
_PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist");
return NULL;
@@ -7186,10 +2341,23 @@ PyEval_GetLocals(void)
}
PyObject *
+_PyEval_GetFrameLocals(void)
+{
+ PyThreadState *tstate = _PyThreadState_GET();
+ _PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate);
+ if (current_frame == NULL) {
+ _PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist");
+ return NULL;
+ }
+
+ return _PyFrame_GetLocals(current_frame, 1);
+}
+
+PyObject *
PyEval_GetGlobals(void)
{
PyThreadState *tstate = _PyThreadState_GET();
- _PyInterpreterFrame *current_frame = tstate->cframe->current_frame;
+ _PyInterpreterFrame *current_frame = _PyThreadState_GetFrame(tstate);
if (current_frame == NULL) {
return NULL;
}
@@ -7241,114 +2409,6 @@ PyEval_GetFuncDesc(PyObject *func)
return " object";
}
-#define C_TRACE(x, call) \
-if (use_tracing && tstate->c_profilefunc) { \
- if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
- tstate, tstate->cframe->current_frame, \
- PyTrace_C_CALL, func)) { \
- x = NULL; \
- } \
- else { \
- x = call; \
- if (tstate->c_profilefunc != NULL) { \
- if (x == NULL) { \
- call_trace_protected(tstate->c_profilefunc, \
- tstate->c_profileobj, \
- tstate, tstate->cframe->current_frame, \
- PyTrace_C_EXCEPTION, func); \
- /* XXX should pass (type, value, tb) */ \
- } else { \
- if (call_trace(tstate->c_profilefunc, \
- tstate->c_profileobj, \
- tstate, tstate->cframe->current_frame, \
- PyTrace_C_RETURN, func)) { \
- Py_DECREF(x); \
- x = NULL; \
- } \
- } \
- } \
- } \
-} else { \
- x = call; \
- }
-
-
-static PyObject *
-trace_call_function(PyThreadState *tstate,
- PyObject *func,
- PyObject **args, Py_ssize_t nargs,
- PyObject *kwnames)
-{
- int use_tracing = 1;
- PyObject *x;
- if (PyCFunction_CheckExact(func) || PyCMethod_CheckExact(func)) {
- C_TRACE(x, PyObject_Vectorcall(func, args, nargs, kwnames));
- return x;
- }
- else if (Py_IS_TYPE(func, &PyMethodDescr_Type) && nargs > 0) {
- /* We need to create a temporary bound method as argument
- for profiling.
-
- If nargs == 0, then this cannot work because we have no
- "self". In any case, the call itself would raise
- TypeError (foo needs an argument), so we just skip
- profiling. */
- PyObject *self = args[0];
- func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self));
- if (func == NULL) {
- return NULL;
- }
- C_TRACE(x, PyObject_Vectorcall(func,
- args+1, nargs-1,
- kwnames));
- Py_DECREF(func);
- return x;
- }
- return PyObject_Vectorcall(func, args, nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
-}
-
-static PyObject *
-do_call_core(PyThreadState *tstate,
- PyObject *func,
- PyObject *callargs,
- PyObject *kwdict,
- int use_tracing
- )
-{
- PyObject *result;
-
- if (PyCFunction_CheckExact(func) || PyCMethod_CheckExact(func)) {
- C_TRACE(result, PyObject_Call(func, callargs, kwdict));
- return result;
- }
- else if (Py_IS_TYPE(func, &PyMethodDescr_Type)) {
- Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
- if (nargs > 0 && use_tracing) {
- /* We need to create a temporary bound method as argument
- for profiling.
-
- If nargs == 0, then this cannot work because we have no
- "self". In any case, the call itself would raise
- TypeError (foo needs an argument), so we just skip
- profiling. */
- PyObject *self = PyTuple_GET_ITEM(callargs, 0);
- func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self));
- if (func == NULL) {
- return NULL;
- }
-
- C_TRACE(result, _PyObject_FastCallDictTstate(
- tstate, func,
- &_PyTuple_ITEMS(callargs)[1],
- nargs - 1,
- kwdict));
- Py_DECREF(func);
- return result;
- }
- }
- return PyObject_Call(func, callargs, kwdict);
-}
-
/* Extract a slice index from a PyLong or an object with the
nb_index slot defined, and store in *pi.
Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
@@ -7413,7 +2473,7 @@ import_name(PyThreadState *tstate, _PyInterpreterFrame *frame,
}
PyObject *locals = frame->f_locals;
/* Fast path for not overloaded __import__. */
- if (import_func == tstate->interp->import_func) {
+ if (_PyImport_IsDefaultImportFunc(tstate->interp, import_func)) {
Py_DECREF(import_func);
int ilevel = _PyLong_AsInt(level);
if (ilevel == -1 && _PyErr_Occurred(tstate)) {
@@ -7489,7 +2549,7 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
name, pkgname_or_unknown
);
/* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */
- PyErr_SetImportError(errmsg, pkgname, NULL);
+ _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, NULL, name);
}
else {
PyObject *spec = PyObject_GetAttr(v, &_Py_ID(__spec__));
@@ -7502,7 +2562,7 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
errmsg = PyUnicode_FromFormat(fmt, name, pkgname_or_unknown, pkgpath);
/* NULL checks for errmsg and pkgname done by PyErr_SetImportError. */
- PyErr_SetImportError(errmsg, pkgname, pkgpath);
+ _PyErr_SetImportErrorWithNameFrom(errmsg, pkgname, pkgpath, name);
}
Py_XDECREF(errmsg);
@@ -7511,95 +2571,6 @@ import_from(PyThreadState *tstate, PyObject *v, PyObject *name)
return NULL;
}
-static int
-import_all_from(PyThreadState *tstate, PyObject *locals, PyObject *v)
-{
- PyObject *all, *dict, *name, *value;
- int skip_leading_underscores = 0;
- int pos, err;
-
- if (_PyObject_LookupAttr(v, &_Py_ID(__all__), &all) < 0) {
- return -1; /* Unexpected error */
- }
- if (all == NULL) {
- if (_PyObject_LookupAttr(v, &_Py_ID(__dict__), &dict) < 0) {
- return -1;
- }
- if (dict == NULL) {
- _PyErr_SetString(tstate, PyExc_ImportError,
- "from-import-* object has no __dict__ and no __all__");
- return -1;
- }
- all = PyMapping_Keys(dict);
- Py_DECREF(dict);
- if (all == NULL)
- return -1;
- skip_leading_underscores = 1;
- }
-
- for (pos = 0, err = 0; ; pos++) {
- name = PySequence_GetItem(all, pos);
- if (name == NULL) {
- if (!_PyErr_ExceptionMatches(tstate, PyExc_IndexError)) {
- err = -1;
- }
- else {
- _PyErr_Clear(tstate);
- }
- break;
- }
- if (!PyUnicode_Check(name)) {
- PyObject *modname = PyObject_GetAttr(v, &_Py_ID(__name__));
- if (modname == NULL) {
- Py_DECREF(name);
- err = -1;
- break;
- }
- if (!PyUnicode_Check(modname)) {
- _PyErr_Format(tstate, PyExc_TypeError,
- "module __name__ must be a string, not %.100s",
- Py_TYPE(modname)->tp_name);
- }
- else {
- _PyErr_Format(tstate, PyExc_TypeError,
- "%s in %U.%s must be str, not %.100s",
- skip_leading_underscores ? "Key" : "Item",
- modname,
- skip_leading_underscores ? "__dict__" : "__all__",
- Py_TYPE(name)->tp_name);
- }
- Py_DECREF(modname);
- Py_DECREF(name);
- err = -1;
- break;
- }
- if (skip_leading_underscores) {
- if (PyUnicode_READY(name) == -1) {
- Py_DECREF(name);
- err = -1;
- break;
- }
- if (PyUnicode_READ_CHAR(name, 0) == '_') {
- Py_DECREF(name);
- continue;
- }
- }
- value = PyObject_GetAttr(v, name);
- if (value == NULL)
- err = -1;
- else if (PyDict_CheckExact(locals))
- err = PyDict_SetItem(locals, name, value);
- else
- err = PyObject_SetItem(locals, name, value);
- Py_DECREF(name);
- Py_XDECREF(value);
- if (err != 0)
- break;
- }
- Py_DECREF(all);
- return err;
-}
-
#define CANNOT_CATCH_MSG "catching classes that do not inherit from "\
"BaseException is not allowed"
@@ -7709,13 +2680,13 @@ format_kwargs_error(PyThreadState *tstate, PyObject *func, PyObject *kwargs)
}
}
else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
- PyObject *exc, *val, *tb;
- _PyErr_Fetch(tstate, &exc, &val, &tb);
- if (val && PyTuple_Check(val) && PyTuple_GET_SIZE(val) == 1) {
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ PyObject *args = ((PyBaseExceptionObject *)exc)->args;
+ if (exc && PyTuple_Check(args) && PyTuple_GET_SIZE(args) == 1) {
_PyErr_Clear(tstate);
PyObject *funcstr = _PyObject_FunctionStr(func);
if (funcstr != NULL) {
- PyObject *key = PyTuple_GET_ITEM(val, 0);
+ PyObject *key = PyTuple_GET_ITEM(args, 0);
_PyErr_Format(
tstate, PyExc_TypeError,
"%U got multiple values for keyword argument '%S'",
@@ -7723,11 +2694,9 @@ format_kwargs_error(PyThreadState *tstate, PyObject *func, PyObject *kwargs)
Py_DECREF(funcstr);
}
Py_XDECREF(exc);
- Py_XDECREF(val);
- Py_XDECREF(tb);
}
else {
- _PyErr_Restore(tstate, exc, val, tb);
+ _PyErr_SetRaisedException(tstate, exc);
}
}
}
@@ -7749,18 +2718,15 @@ format_exc_check_arg(PyThreadState *tstate, PyObject *exc,
if (exc == PyExc_NameError) {
// Include the name in the NameError exceptions to offer suggestions later.
- PyObject *type, *value, *traceback;
- PyErr_Fetch(&type, &value, &traceback);
- PyErr_NormalizeException(&type, &value, &traceback);
- if (PyErr_GivenExceptionMatches(value, PyExc_NameError)) {
- PyNameErrorObject* exc = (PyNameErrorObject*) value;
- if (exc->name == NULL) {
+ PyObject *exc = PyErr_GetRaisedException();
+ if (PyErr_GivenExceptionMatches(exc, PyExc_NameError)) {
+ if (((PyNameErrorObject*)exc)->name == NULL) {
// We do not care if this fails because we are going to restore the
// NameError anyway.
- (void)PyObject_SetAttr(value, &_Py_ID(name), obj);
+ (void)PyObject_SetAttr(exc, &_Py_ID(name), obj);
}
}
- PyErr_Restore(type, value, traceback);
+ PyErr_SetRaisedException(exc);
}
}
@@ -7772,7 +2738,7 @@ format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg)
if (_PyErr_Occurred(tstate))
return;
name = PyTuple_GET_ITEM(co->co_localsplusnames, oparg);
- if (oparg < co->co_nplaincellvars + co->co_nlocals) {
+ if (oparg < PyCode_GetFirstFree(co)) {
format_exc_check_arg(tstate, PyExc_UnboundLocalError,
UNBOUNDLOCAL_ERROR_MSG, name);
} else {
@@ -7800,64 +2766,9 @@ format_awaitable_error(PyThreadState *tstate, PyTypeObject *type, int oparg)
}
}
-#ifdef Py_STATS
-
-static PyObject *
-getarray(uint64_t a[256])
-{
- int i;
- PyObject *l = PyList_New(256);
- if (l == NULL) return NULL;
- for (i = 0; i < 256; i++) {
- PyObject *x = PyLong_FromUnsignedLongLong(a[i]);
- if (x == NULL) {
- Py_DECREF(l);
- return NULL;
- }
- PyList_SET_ITEM(l, i, x);
- }
- for (i = 0; i < 256; i++)
- a[i] = 0;
- return l;
-}
-
-PyObject *
-_Py_GetDXProfile(PyObject *self, PyObject *args)
-{
- int i;
- PyObject *l = PyList_New(257);
- if (l == NULL) return NULL;
- for (i = 0; i < 256; i++) {
- PyObject *x = getarray(_py_stats.opcode_stats[i].pair_count);
- if (x == NULL) {
- Py_DECREF(l);
- return NULL;
- }
- PyList_SET_ITEM(l, i, x);
- }
- PyObject *counts = PyList_New(256);
- if (counts == NULL) {
- Py_DECREF(l);
- return NULL;
- }
- for (i = 0; i < 256; i++) {
- PyObject *x = PyLong_FromUnsignedLongLong(
- _py_stats.opcode_stats[i].execution_count);
- if (x == NULL) {
- Py_DECREF(counts);
- Py_DECREF(l);
- return NULL;
- }
- PyList_SET_ITEM(counts, i, x);
- }
- PyList_SET_ITEM(l, 256, counts);
- return l;
-}
-
-#endif
Py_ssize_t
-_PyEval_RequestCodeExtraIndex(freefunc free)
+PyUnstable_Eval_RequestCodeExtraIndex(freefunc free)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
Py_ssize_t new_index;
@@ -7870,81 +2781,14 @@ _PyEval_RequestCodeExtraIndex(freefunc free)
return new_index;
}
-static void
-dtrace_function_entry(_PyInterpreterFrame *frame)
-{
- const char *filename;
- const char *funcname;
- int lineno;
-
- PyCodeObject *code = frame->f_code;
- filename = PyUnicode_AsUTF8(code->co_filename);
- funcname = PyUnicode_AsUTF8(code->co_name);
- lineno = _PyInterpreterFrame_GetLine(frame);
-
- PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
-}
-
-static void
-dtrace_function_return(_PyInterpreterFrame *frame)
-{
- const char *filename;
- const char *funcname;
- int lineno;
-
- PyCodeObject *code = frame->f_code;
- filename = PyUnicode_AsUTF8(code->co_filename);
- funcname = PyUnicode_AsUTF8(code->co_name);
- lineno = _PyInterpreterFrame_GetLine(frame);
-
- PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
-}
-
-/* DTrace equivalent of maybe_call_line_trace. */
-static void
-maybe_dtrace_line(_PyInterpreterFrame *frame,
- PyTraceInfo *trace_info,
- int instr_prev)
-{
- const char *co_filename, *co_name;
-
- /* If the last instruction executed isn't in the current
- instruction window, reset the window.
- */
- initialize_trace_info(trace_info, frame);
- int lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &trace_info->bounds);
- int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
- int line = _PyCode_CheckLineNumber(addr, &trace_info->bounds);
- if (line != -1) {
- /* Trace backward edges or first instruction of a new line */
- if (_PyInterpreterFrame_LASTI(frame) < instr_prev ||
- (line != lastline && addr == trace_info->bounds.ar_start))
- {
- co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
- if (!co_filename) {
- co_filename = "?";
- }
- co_name = PyUnicode_AsUTF8(frame->f_code->co_name);
- if (!co_name) {
- co_name = "?";
- }
- PyDTrace_LINE(co_filename, co_name, line);
- }
- }
-}
-
/* Implement Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() as functions
for the limited API. */
-#undef Py_EnterRecursiveCall
-
int Py_EnterRecursiveCall(const char *where)
{
return _Py_EnterRecursiveCall(where);
}
-#undef Py_LeaveRecursiveCall
-
void Py_LeaveRecursiveCall(void)
{
_Py_LeaveRecursiveCall();