summaryrefslogtreecommitdiffstats
path: root/Python/ceval.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/ceval.c')
-rw-r--r--Python/ceval.c1910
1 files changed, 1020 insertions, 890 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index 9f1af78..82cc9a2 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -15,87 +15,12 @@
#include "dictobject.h"
#include "frameobject.h"
#include "opcode.h"
+#include "pydtrace.h"
#include "setobject.h"
#include "structmember.h"
#include <ctype.h>
-#ifndef WITH_TSC
-
-#define READ_TIMESTAMP(var)
-
-#else
-
-typedef unsigned long long uint64;
-
-/* PowerPC support.
- "__ppc__" appears to be the preprocessor definition to detect on OS X, whereas
- "__powerpc__" appears to be the correct one for Linux with GCC
-*/
-#if defined(__ppc__) || defined (__powerpc__)
-
-#define READ_TIMESTAMP(var) ppc_getcounter(&var)
-
-static void
-ppc_getcounter(uint64 *v)
-{
- unsigned long tbu, tb, tbu2;
-
- loop:
- asm volatile ("mftbu %0" : "=r" (tbu) );
- asm volatile ("mftb %0" : "=r" (tb) );
- asm volatile ("mftbu %0" : "=r" (tbu2));
- if (__builtin_expect(tbu != tbu2, 0)) goto loop;
-
- /* The slightly peculiar way of writing the next lines is
- compiled better by GCC than any other way I tried. */
- ((long*)(v))[0] = tbu;
- ((long*)(v))[1] = tb;
-}
-
-#elif defined(__i386__)
-
-/* this is for linux/x86 (and probably any other GCC/x86 combo) */
-
-#define READ_TIMESTAMP(val) \
- __asm__ __volatile__("rdtsc" : "=A" (val))
-
-#elif defined(__x86_64__)
-
-/* for gcc/x86_64, the "A" constraint in DI mode means *either* rax *or* rdx;
- not edx:eax as it does for i386. Since rdtsc puts its result in edx:eax
- even in 64-bit mode, we need to use "a" and "d" for the lower and upper
- 32-bit pieces of the result. */
-
-#define READ_TIMESTAMP(val) do { \
- unsigned int h, l; \
- __asm__ __volatile__("rdtsc" : "=a" (l), "=d" (h)); \
- (val) = ((uint64)l) | (((uint64)h) << 32); \
- } while(0)
-
-
-#else
-
-#error "Don't know how to implement timestamp counter for this architecture"
-
-#endif
-
-void dump_tsc(int opcode, int ticked, uint64 inst0, uint64 inst1,
- uint64 loop0, uint64 loop1, uint64 intr0, uint64 intr1)
-{
- uint64 intr, inst, loop;
- PyThreadState *tstate = PyThreadState_Get();
- if (!tstate->interp->tscdump)
- return;
- intr = intr1 - intr0;
- inst = inst1 - inst0 - intr;
- loop = loop1 - loop0 - intr;
- fprintf(stderr, "opcode=%03d t=%d inst=%06lld loop=%06lld\n",
- opcode, ticked, inst, loop);
-}
-
-#endif
-
/* Turn this on if your compiler chokes on the big switch: */
/* #define CASE_TOO_BIG 1 */
@@ -108,24 +33,13 @@ void dump_tsc(int opcode, int ticked, uint64 inst0, uint64 inst1,
typedef PyObject *(*callproc)(PyObject *, PyObject *, PyObject *);
/* Forward declarations */
-#ifdef WITH_TSC
-static PyObject * call_function(PyObject ***, int, uint64*, uint64*);
-#else
-static PyObject * call_function(PyObject ***, int);
-#endif
-static PyObject * fast_function(PyObject *, PyObject ***, int, int, int);
-static PyObject * do_call(PyObject *, PyObject ***, int, int);
-static PyObject * ext_do_call(PyObject *, PyObject ***, int, int, int);
-static PyObject * update_keyword_args(PyObject *, int, PyObject ***,
- PyObject *);
-static PyObject * update_star_args(int, int, PyObject *, PyObject ***);
-static PyObject * load_args(PyObject ***, int);
-#define CALL_FLAG_VAR 1
-#define CALL_FLAG_KW 2
+static PyObject * call_function(PyObject ***, Py_ssize_t, PyObject *);
+static PyObject * fast_function(PyObject *, PyObject **, Py_ssize_t, PyObject *);
+static PyObject * do_call_core(PyObject *, PyObject *, PyObject *);
#ifdef LLTRACE
static int lltrace;
-static int prtrace(PyObject *, char *);
+static int prtrace(PyObject *, const char *);
#endif
static int call_trace(Py_tracefunc, PyObject *,
PyThreadState *, PyFrameObject *,
@@ -137,14 +51,18 @@ static void call_exc_trace(Py_tracefunc, PyObject *,
PyThreadState *, PyFrameObject *);
static int maybe_call_line_trace(Py_tracefunc, PyObject *,
PyThreadState *, PyFrameObject *, int *, int *, int *);
+static void maybe_dtrace_line(PyFrameObject *, int *, int *, int *);
+static void dtrace_function_entry(PyFrameObject *);
+static void dtrace_function_return(PyFrameObject *);
static PyObject * cmp_outcome(int, PyObject *, PyObject *);
+static PyObject * import_name(PyFrameObject *, PyObject *, PyObject *, PyObject *);
static PyObject * import_from(PyObject *, PyObject *);
static int import_all_from(PyObject *, PyObject *);
static void format_exc_check_arg(PyObject *, const char *, PyObject *);
static void format_exc_unbound(PyCodeObject *co, int oparg);
static PyObject * unicode_concatenate(PyObject *, PyObject *,
- PyFrameObject *, unsigned char *);
+ PyFrameObject *, const _Py_CODEUNIT *);
static PyObject * special_lookup(PyObject *, _Py_Identifier *);
#define NAME_ERROR_MSG \
@@ -796,11 +714,18 @@ PyEval_EvalFrame(PyFrameObject *f) {
PyObject *
PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
{
+ PyThreadState *tstate = PyThreadState_GET();
+ return tstate->interp->eval_frame(f, throwflag);
+}
+
+PyObject *
+_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
+{
#ifdef DXPAIRS
int lastopcode = 0;
#endif
PyObject **stack_pointer; /* Next free slot in value stack */
- unsigned char *next_instr;
+ const _Py_CODEUNIT *next_instr;
int opcode; /* Current opcode */
int oparg; /* Current opcode argument, if any */
enum why_code why; /* Reason for block stack unwind */
@@ -818,7 +743,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
time it is tested. */
int instr_ub = -1, instr_lb = 0, instr_prev = -1;
- unsigned char *first_instr;
+ const _Py_CODEUNIT *first_instr;
PyObject *names;
PyObject *consts;
@@ -886,24 +811,10 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
/* Import the static jump table */
#include "opcode_targets.h"
-/* This macro is used when several opcodes defer to the same implementation
- (e.g. SETUP_LOOP, SETUP_FINALLY) */
-#define TARGET_WITH_IMPL(op, impl) \
- TARGET_##op: \
- opcode = op; \
- if (HAS_ARG(op)) \
- oparg = NEXTARG(); \
- case op: \
- goto impl; \
-
#define TARGET(op) \
TARGET_##op: \
- opcode = op; \
- if (HAS_ARG(op)) \
- oparg = NEXTARG(); \
case op:
-
#define DISPATCH() \
{ \
if (!_Py_atomic_load_relaxed(&eval_breaker)) { \
@@ -915,18 +826,20 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#ifdef LLTRACE
#define FAST_DISPATCH() \
{ \
- if (!lltrace && !_Py_TracingPossible) { \
+ if (!lltrace && !_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
- goto *opcode_targets[*next_instr++]; \
+ NEXTOPARG(); \
+ goto *opcode_targets[opcode]; \
} \
goto fast_next_opcode; \
}
#else
#define FAST_DISPATCH() \
{ \
- if (!_Py_TracingPossible) { \
+ if (!_Py_TracingPossible && !PyDTrace_LINE_ENABLED()) { \
f->f_lasti = INSTR_OFFSET(); \
- goto *opcode_targets[*next_instr++]; \
+ NEXTOPARG(); \
+ goto *opcode_targets[opcode]; \
} \
goto fast_next_opcode; \
}
@@ -935,10 +848,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#else
#define TARGET(op) \
case op:
-#define TARGET_WITH_IMPL(op, impl) \
- /* silence compiler warnings about `impl` unused */ \
- if (0) goto impl; \
- case op:
+
#define DISPATCH() continue
#define FAST_DISPATCH() goto fast_next_opcode
#endif
@@ -952,70 +862,33 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#define GETITEM(v, i) PyTuple_GetItem((v), (i))
#endif
-#ifdef WITH_TSC
-/* Use Pentium timestamp counter to mark certain events:
- inst0 -- beginning of switch statement for opcode dispatch
- inst1 -- end of switch statement (may be skipped)
- loop0 -- the top of the mainloop
- loop1 -- place where control returns again to top of mainloop
- (may be skipped)
- intr1 -- beginning of long interruption
- intr2 -- end of long interruption
-
- Many opcodes call out to helper C functions. In some cases, the
- time in those functions should be counted towards the time for the
- opcode, but not in all cases. For example, a CALL_FUNCTION opcode
- calls another Python function; there's no point in charge all the
- bytecode executed by the called function to the caller.
-
- It's hard to make a useful judgement statically. In the presence
- of operator overloading, it's impossible to tell if a call will
- execute new Python code or not.
-
- It's a case-by-case judgement. I'll use intr1 for the following
- cases:
-
- IMPORT_STAR
- IMPORT_FROM
- CALL_FUNCTION (and friends)
-
- */
- uint64 inst0, inst1, loop0, loop1, intr0 = 0, intr1 = 0;
- int ticked = 0;
-
- READ_TIMESTAMP(inst0);
- READ_TIMESTAMP(inst1);
- READ_TIMESTAMP(loop0);
- READ_TIMESTAMP(loop1);
-
- /* shut up the compiler */
- opcode = 0;
-#endif
-
/* Code access macros */
-#define INSTR_OFFSET() ((int)(next_instr - first_instr))
-#define NEXTOP() (*next_instr++)
-#define NEXTARG() (next_instr += 2, (next_instr[-1]<<8) + next_instr[-2])
-#define PEEKARG() ((next_instr[2]<<8) + next_instr[1])
-#define JUMPTO(x) (next_instr = first_instr + (x))
-#define JUMPBY(x) (next_instr += (x))
+/* The integer overflow is checked by an assertion below. */
+#define INSTR_OFFSET() (sizeof(_Py_CODEUNIT) * (int)(next_instr - first_instr))
+#define NEXTOPARG() do { \
+ _Py_CODEUNIT word = *next_instr; \
+ opcode = _Py_OPCODE(word); \
+ oparg = _Py_OPARG(word); \
+ next_instr++; \
+ } while (0)
+#define JUMPTO(x) (next_instr = first_instr + (x) / sizeof(_Py_CODEUNIT))
+#define JUMPBY(x) (next_instr += (x) / sizeof(_Py_CODEUNIT))
/* 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 JUMP_IF_FALSE or JUMP_IF_TRUE. And,
- those opcodes are often followed by a POP_TOP.
+ 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 two unpredictable branches, the HAS_ARG test and the
- switch-case. 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.
+ 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
@@ -1030,13 +903,19 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#if defined(DYNAMIC_EXECUTION_PROFILE) || USE_COMPUTED_GOTOS
#define PREDICT(op) if (0) goto PRED_##op
-#define PREDICTED(op) PRED_##op:
-#define PREDICTED_WITH_ARG(op) PRED_##op:
#else
-#define PREDICT(op) if (*next_instr == op) goto PRED_##op
-#define PREDICTED(op) PRED_##op: next_instr++
-#define PREDICTED_WITH_ARG(op) PRED_##op: oparg = PEEKARG(); next_instr += 3
+#define PREDICT(op) \
+ do{ \
+ _Py_CODEUNIT word = *next_instr; \
+ opcode = _Py_OPCODE(word); \
+ if (opcode == op){ \
+ oparg = _Py_OPARG(word); \
+ next_instr++; \
+ goto PRED_##op; \
+ } \
+ } while(0)
#endif
+#define PREDICTED(op) PRED_##op:
/* Stack manipulation macros */
@@ -1100,7 +979,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
#define UNWIND_EXCEPT_HANDLER(b) \
- { \
+ do { \
PyObject *type, *value, *traceback; \
assert(STACK_LEVEL() >= (b)->b_level + 3); \
while (STACK_LEVEL() > (b)->b_level + 3) { \
@@ -1116,7 +995,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
Py_XDECREF(type); \
Py_XDECREF(value); \
Py_XDECREF(traceback); \
- }
+ } while(0)
/* Start of code */
@@ -1160,21 +1039,24 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
}
+ if (PyDTrace_FUNCTION_ENTRY_ENABLED())
+ dtrace_function_entry(f);
+
co = f->f_code;
names = co->co_names;
consts = co->co_consts;
fastlocals = f->f_localsplus;
freevars = f->f_localsplus + co->co_nlocals;
- first_instr = (unsigned char*) PyBytes_AS_STRING(co->co_code);
- /* An explanation is in order for the next line.
-
- f->f_lasti now refers to the index of the last instruction
- executed. You might think this was obvious from the name, but
- this wasn't always true before 2.3! PyFrame_New now sets
- f->f_lasti to -1 (i.e. the index *before* the first instruction)
- and YIELD_VALUE doesn't fiddle with f_lasti any more. So this
- does work. Promise.
- YIELD_FROM sets f_lasti to itself, in order to repeated yield
+ assert(PyBytes_Check(co->co_code));
+ assert(PyBytes_GET_SIZE(co->co_code) <= INT_MAX);
+ assert(PyBytes_GET_SIZE(co->co_code) % sizeof(_Py_CODEUNIT) == 0);
+ assert(_Py_IS_ALIGNED(PyBytes_AS_STRING(co->co_code), sizeof(_Py_CODEUNIT)));
+ first_instr = (_Py_CODEUNIT *) PyBytes_AS_STRING(co->co_code);
+ /*
+ f->f_lasti refers to the index of the last instruction,
+ unless it's -1 in which case next_instr should be first_instr.
+
+ YIELD_FROM sets f_lasti to itself, in order to repeatedly yield
multiple values.
When the PREDICT() macros are enabled, some opcode pairs follow in
@@ -1183,15 +1065,20 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
were a single new opcode; accordingly,f->f_lasti will point to
the first code in the pair (for instance, GET_ITER followed by
FOR_ITER is effectively a single opcode and f->f_lasti will point
- at to the beginning of the combined pair.)
+ to the beginning of the combined pair.)
*/
- next_instr = first_instr + f->f_lasti + 1;
+ assert(f->f_lasti >= -1);
+ next_instr = first_instr;
+ if (f->f_lasti >= 0) {
+ assert(f->f_lasti % sizeof(_Py_CODEUNIT) == 0);
+ next_instr += f->f_lasti / sizeof(_Py_CODEUNIT) + 1;
+ }
stack_pointer = f->f_stacktop;
assert(stack_pointer != NULL);
f->f_stacktop = NULL; /* remains NULL unless yield suspends frame */
f->f_executing = 1;
- if (co->co_flags & (CO_GENERATOR | CO_COROUTINE)) {
+ if (co->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
if (!throwflag && f->f_exc_type != NULL && f->f_exc_type != Py_None) {
/* We were in an except handler when we left,
restore the exception state which was put aside
@@ -1219,23 +1106,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#endif
for (;;) {
-#ifdef WITH_TSC
- if (inst1 == 0) {
- /* Almost surely, the opcode executed a break
- or a continue, preventing inst1 from being set
- on the way out of the loop.
- */
- READ_TIMESTAMP(inst1);
- loop1 = inst1;
- }
- dump_tsc(opcode, ticked, inst0, inst1, loop0, loop1,
- intr0, intr1);
- ticked = 0;
- inst1 = 0;
- intr0 = 0;
- intr1 = 0;
- READ_TIMESTAMP(loop0);
-#endif
assert(stack_pointer >= f->f_valuestack); /* else underflow */
assert(STACK_LEVEL() <= co->co_stacksize); /* else overflow */
assert(!PyErr_Occurred());
@@ -1249,14 +1119,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
Py_MakePendingCalls() above. */
if (_Py_atomic_load_relaxed(&eval_breaker)) {
- if (*next_instr == SETUP_FINALLY) {
+ if (_Py_OPCODE(*next_instr) == SETUP_FINALLY) {
/* Make the last opcode before
a try: finally: block uninterruptible. */
goto fast_next_opcode;
}
-#ifdef WITH_TSC
- ticked = 1;
-#endif
if (_Py_atomic_load_relaxed(&pendingcalls_to_do)) {
if (Py_MakePendingCalls() < 0)
goto error;
@@ -1296,6 +1163,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
fast_next_opcode:
f->f_lasti = INSTR_OFFSET();
+ if (PyDTrace_LINE_ENABLED())
+ maybe_dtrace_line(f, &instr_lb, &instr_ub, &instr_prev);
+
/* line-by-line tracing support */
if (_Py_TracingPossible &&
@@ -1322,11 +1192,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
/* Extract opcode and argument */
- opcode = NEXTOP();
- oparg = 0; /* allows oparg to be stored in a register because
- it doesn't have to be remembered across a full loop */
- if (HAS_ARG(opcode))
- oparg = NEXTARG();
+ NEXTOPARG();
dispatch_opcode:
#ifdef DYNAMIC_EXECUTION_PROFILE
#ifdef DXPAIRS
@@ -1351,9 +1217,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
#endif
- /* Main switch on opcode */
- READ_TIMESTAMP(inst0);
-
switch (opcode) {
/* BEWARE!
@@ -1377,6 +1240,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
FAST_DISPATCH();
}
+ PREDICTED(LOAD_CONST);
TARGET(LOAD_CONST) {
PyObject *value = GETITEM(consts, oparg);
Py_INCREF(value);
@@ -1384,7 +1248,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
FAST_DISPATCH();
}
- PREDICTED_WITH_ARG(STORE_FAST);
+ PREDICTED(STORE_FAST);
TARGET(STORE_FAST) {
PyObject *value = POP();
SETLOCAL(oparg, value);
@@ -1863,6 +1727,61 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
+ TARGET(STORE_ANNOTATION) {
+ _Py_IDENTIFIER(__annotations__);
+ PyObject *ann_dict;
+ PyObject *ann = POP();
+ PyObject *name = GETITEM(names, oparg);
+ int err;
+ if (f->f_locals == NULL) {
+ PyErr_Format(PyExc_SystemError,
+ "no locals found when storing annotation");
+ Py_DECREF(ann);
+ goto error;
+ }
+ /* first try to get __annotations__ from locals... */
+ if (PyDict_CheckExact(f->f_locals)) {
+ ann_dict = _PyDict_GetItemId(f->f_locals,
+ &PyId___annotations__);
+ if (ann_dict == NULL) {
+ PyErr_SetString(PyExc_NameError,
+ "__annotations__ not found");
+ Py_DECREF(ann);
+ goto error;
+ }
+ Py_INCREF(ann_dict);
+ }
+ else {
+ PyObject *ann_str = _PyUnicode_FromId(&PyId___annotations__);
+ if (ann_str == NULL) {
+ Py_DECREF(ann);
+ goto error;
+ }
+ ann_dict = PyObject_GetItem(f->f_locals, ann_str);
+ if (ann_dict == NULL) {
+ if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyErr_SetString(PyExc_NameError,
+ "__annotations__ not found");
+ }
+ Py_DECREF(ann);
+ goto error;
+ }
+ }
+ /* ...if succeeded, __annotations__[name] = ann */
+ if (PyDict_CheckExact(ann_dict)) {
+ err = PyDict_SetItem(ann_dict, name, ann);
+ }
+ else {
+ err = PyObject_SetItem(ann_dict, name, ann);
+ }
+ Py_DECREF(ann_dict);
+ Py_DECREF(ann);
+ if (err != 0) {
+ goto error;
+ }
+ DISPATCH();
+ }
+
TARGET(DELETE_SUBSCR) {
PyObject *sub = TOP();
PyObject *container = SECOND();
@@ -2006,6 +1925,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
SET_TOP(awaitable);
+ PREDICT(LOAD_CONST);
DISPATCH();
}
@@ -2016,41 +1936,52 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
PyObject *aiter = TOP();
PyTypeObject *type = Py_TYPE(aiter);
- if (type->tp_as_async != NULL)
- getter = type->tp_as_async->am_anext;
+ 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) {
+ if (getter != NULL) {
+ next_iter = (*getter)(aiter);
+ if (next_iter == NULL) {
+ goto error;
+ }
+ }
+ else {
+ PyErr_Format(
+ PyExc_TypeError,
+ "'async for' requires an iterator with "
+ "__anext__ method, got %.100s",
+ type->tp_name);
goto error;
}
- }
- else {
- PyErr_Format(
- 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_Format(
- PyExc_TypeError,
- "'async for' received an invalid object "
- "from __anext__: %.100s",
- Py_TYPE(next_iter)->tp_name);
+ awaitable = _PyCoro_GetAwaitableIter(next_iter);
+ if (awaitable == NULL) {
+ PyErr_Format(
+ 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);
+ Py_DECREF(next_iter);
+ goto error;
+ } else {
+ Py_DECREF(next_iter);
+ }
+ }
PUSH(awaitable);
+ PREDICT(LOAD_CONST);
DISPATCH();
}
+ PREDICTED(GET_AWAITABLE);
TARGET(GET_AWAITABLE) {
PyObject *iterable = TOP();
PyObject *iter = _PyCoro_GetAwaitableIter(iterable);
@@ -2078,21 +2009,22 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
goto error;
}
+ PREDICT(LOAD_CONST);
DISPATCH();
}
TARGET(YIELD_FROM) {
PyObject *v = POP();
- PyObject *reciever = TOP();
+ PyObject *receiver = TOP();
int err;
- if (PyGen_CheckExact(reciever) || PyCoro_CheckExact(reciever)) {
- retval = _PyGen_Send((PyGenObject *)reciever, v);
+ if (PyGen_CheckExact(receiver) || PyCoro_CheckExact(receiver)) {
+ retval = _PyGen_Send((PyGenObject *)receiver, v);
} else {
_Py_IDENTIFIER(send);
if (v == Py_None)
- retval = Py_TYPE(reciever)->tp_iternext(reciever);
+ retval = Py_TYPE(receiver)->tp_iternext(receiver);
else
- retval = _PyObject_CallMethodIdObjArgs(reciever, &PyId_send, v, NULL);
+ retval = _PyObject_CallMethodIdObjArgs(receiver, &PyId_send, v, NULL);
}
Py_DECREF(v);
if (retval == NULL) {
@@ -2103,7 +2035,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
err = _PyGen_FetchStopIterationValue(&val);
if (err < 0)
goto error;
- Py_DECREF(reciever);
+ Py_DECREF(receiver);
SET_TOP(val);
DISPATCH();
}
@@ -2111,12 +2043,23 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
f->f_stacktop = stack_pointer;
why = WHY_YIELD;
/* and repeat... */
- f->f_lasti--;
+ f->f_lasti -= sizeof(_Py_CODEUNIT);
goto fast_yield;
}
TARGET(YIELD_VALUE) {
retval = POP();
+
+ if (co->co_flags & CO_ASYNC_GENERATOR) {
+ PyObject *w = _PyAsyncGenValueWrapperNew(retval);
+ Py_DECREF(retval);
+ if (w == NULL) {
+ retval = NULL;
+ goto error;
+ }
+ retval = w;
+ }
+
f->f_stacktop = stack_pointer;
why = WHY_YIELD;
goto fast_yield;
@@ -2133,6 +2076,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
+ PREDICTED(POP_BLOCK);
TARGET(POP_BLOCK) {
PyTryBlock *b = PyFrame_BlockPop(f);
UNWIND_BLOCK(b);
@@ -2249,7 +2193,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
- PREDICTED_WITH_ARG(UNPACK_SEQUENCE);
+ PREDICTED(UNPACK_SEQUENCE);
TARGET(UNPACK_SEQUENCE) {
PyObject *seq = POP(), *item, **items;
if (PyTuple_CheckExact(seq) &&
@@ -2358,7 +2302,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
else {
v = PyObject_GetItem(locals, name);
- if (v == NULL && _PyErr_OCCURRED()) {
+ if (v == NULL) {
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
PyErr_Clear();
@@ -2398,26 +2342,33 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
PyObject *name = GETITEM(names, oparg);
PyObject *v;
if (PyDict_CheckExact(f->f_globals)
- && PyDict_CheckExact(f->f_builtins)) {
+ && PyDict_CheckExact(f->f_builtins))
+ {
v = _PyDict_LoadGlobal((PyDictObject *)f->f_globals,
(PyDictObject *)f->f_builtins,
name);
if (v == NULL) {
- if (!_PyErr_OCCURRED())
+ if (!_PyErr_OCCURRED()) {
+ /* _PyDict_LoadGlobal() returns NULL without raising
+ * an exception if the key doesn't exist */
format_exc_check_arg(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(f->f_globals, name);
if (v == NULL) {
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
PyErr_Clear();
+ /* namespace 2: builtins */
v = PyObject_GetItem(f->f_builtins, name);
if (v == NULL) {
if (PyErr_ExceptionMatches(PyExc_KeyError))
@@ -2477,7 +2428,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
else {
value = PyObject_GetItem(locals, name);
- if (value == NULL && PyErr_Occurred()) {
+ if (value == NULL) {
if (!PyErr_ExceptionMatches(PyExc_KeyError))
goto error;
PyErr_Clear();
@@ -2516,6 +2467,24 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
+ TARGET(BUILD_STRING) {
+ PyObject *str;
+ PyObject *empty = PyUnicode_New(0, 0);
+ if (empty == NULL) {
+ goto error;
+ }
+ str = _PyUnicode_JoinArray(empty, stack_pointer - oparg, oparg);
+ Py_DECREF(empty);
+ 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)
@@ -2540,13 +2509,14 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
- TARGET_WITH_IMPL(BUILD_TUPLE_UNPACK, _build_list_unpack)
- TARGET(BUILD_LIST_UNPACK)
- _build_list_unpack: {
- int convert_to_tuple = opcode == BUILD_TUPLE_UNPACK;
- int i;
+ TARGET(BUILD_TUPLE_UNPACK_WITH_CALL)
+ TARGET(BUILD_TUPLE_UNPACK)
+ TARGET(BUILD_LIST_UNPACK) {
+ int convert_to_tuple = opcode != BUILD_LIST_UNPACK;
+ Py_ssize_t i;
PyObject *sum = PyList_New(0);
PyObject *return_value;
+
if (sum == NULL)
goto error;
@@ -2555,6 +2525,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
none_val = _PyList_Extend((PyListObject *)sum, PEEK(i));
if (none_val == NULL) {
+ if (opcode == BUILD_TUPLE_UNPACK_WITH_CALL &&
+ PyErr_ExceptionMatches(PyExc_TypeError)) {
+ PyObject *func = PEEK(1 + oparg);
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%.200s argument after * "
+ "must be an iterable, not %.200s",
+ PyEval_GetFuncName(func),
+ PyEval_GetFuncDesc(func),
+ PEEK(i)->ob_type->tp_name);
+ }
Py_DECREF(sum);
goto error;
}
@@ -2599,7 +2579,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
TARGET(BUILD_SET_UNPACK) {
- int i;
+ Py_ssize_t i;
PyObject *sum = PySet_New(NULL);
if (sum == NULL)
goto error;
@@ -2618,7 +2598,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
TARGET(BUILD_MAP) {
- int i;
+ Py_ssize_t i;
PyObject *map = _PyDict_NewPresized((Py_ssize_t)oparg);
if (map == NULL)
goto error;
@@ -2641,70 +2621,103 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
- TARGET_WITH_IMPL(BUILD_MAP_UNPACK_WITH_CALL, _build_map_unpack)
- TARGET(BUILD_MAP_UNPACK)
- _build_map_unpack: {
- int with_call = opcode == BUILD_MAP_UNPACK_WITH_CALL;
- int num_maps;
- int i;
- PyObject *sum = PyDict_New();
- if (sum == NULL)
+ TARGET(SETUP_ANNOTATIONS) {
+ _Py_IDENTIFIER(__annotations__);
+ int err;
+ PyObject *ann_dict;
+ if (f->f_locals == NULL) {
+ PyErr_Format(PyExc_SystemError,
+ "no locals found when setting up annotations");
goto error;
- if (with_call) {
- num_maps = oparg & 0xff;
}
- else {
- num_maps = oparg;
+ /* check if __annotations__ in locals()... */
+ if (PyDict_CheckExact(f->f_locals)) {
+ ann_dict = _PyDict_GetItemId(f->f_locals,
+ &PyId___annotations__);
+ if (ann_dict == NULL) {
+ /* ...if not, create a new one */
+ ann_dict = PyDict_New();
+ if (ann_dict == NULL) {
+ goto error;
+ }
+ err = _PyDict_SetItemId(f->f_locals,
+ &PyId___annotations__, ann_dict);
+ Py_DECREF(ann_dict);
+ if (err != 0) {
+ goto error;
+ }
+ }
}
-
- for (i = num_maps; i > 0; i--) {
- PyObject *arg = PEEK(i);
- if (with_call) {
- PyObject *intersection = _PyDictView_Intersect(sum, arg);
-
- if (intersection == NULL) {
- if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
- int function_location = (oparg>>8) & 0xff;
- PyObject *func = (
- PEEK(function_location + num_maps));
- PyErr_Format(PyExc_TypeError,
- "%.200s%.200s argument after ** "
- "must be a mapping, not %.200s",
- PyEval_GetFuncName(func),
- PyEval_GetFuncDesc(func),
- arg->ob_type->tp_name);
- }
- Py_DECREF(sum);
+ else {
+ /* do the same if locals() is not a dict */
+ PyObject *ann_str = _PyUnicode_FromId(&PyId___annotations__);
+ if (ann_str == NULL) {
+ break;
+ }
+ ann_dict = PyObject_GetItem(f->f_locals, ann_str);
+ if (ann_dict == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_KeyError)) {
goto error;
}
-
- if (PySet_GET_SIZE(intersection)) {
- Py_ssize_t idx = 0;
- PyObject *key;
- int function_location = (oparg>>8) & 0xff;
- PyObject *func = PEEK(function_location + num_maps);
- Py_hash_t hash;
- _PySet_NextEntry(intersection, &idx, &key, &hash);
- if (!PyUnicode_Check(key)) {
- PyErr_Format(PyExc_TypeError,
- "%.200s%.200s keywords must be strings",
- PyEval_GetFuncName(func),
- PyEval_GetFuncDesc(func));
- } else {
- PyErr_Format(PyExc_TypeError,
- "%.200s%.200s got multiple "
- "values for keyword argument '%U'",
- PyEval_GetFuncName(func),
- PyEval_GetFuncDesc(func),
- key);
- }
- Py_DECREF(intersection);
- Py_DECREF(sum);
+ PyErr_Clear();
+ ann_dict = PyDict_New();
+ if (ann_dict == NULL) {
+ goto error;
+ }
+ err = PyObject_SetItem(f->f_locals, ann_str, ann_dict);
+ Py_DECREF(ann_dict);
+ if (err != 0) {
goto error;
}
- Py_DECREF(intersection);
}
+ else {
+ Py_DECREF(ann_dict);
+ }
+ }
+ DISPATCH();
+ }
+ TARGET(BUILD_CONST_KEY_MAP) {
+ Py_ssize_t i;
+ PyObject *map;
+ PyObject *keys = TOP();
+ if (!PyTuple_CheckExact(keys) ||
+ PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) {
+ PyErr_SetString(PyExc_SystemError,
+ "bad BUILD_CONST_KEY_MAP keys argument");
+ goto error;
+ }
+ map = _PyDict_NewPresized((Py_ssize_t)oparg);
+ if (map == NULL) {
+ goto error;
+ }
+ for (i = oparg; i > 0; i--) {
+ int err;
+ PyObject *key = PyTuple_GET_ITEM(keys, oparg - i);
+ PyObject *value = PEEK(i + 1);
+ err = PyDict_SetItem(map, key, value);
+ if (err != 0) {
+ Py_DECREF(map);
+ goto error;
+ }
+ }
+
+ Py_DECREF(POP());
+ while (oparg--) {
+ Py_DECREF(POP());
+ }
+ PUSH(map);
+ DISPATCH();
+ }
+
+ TARGET(BUILD_MAP_UNPACK) {
+ Py_ssize_t i;
+ PyObject *sum = PyDict_New();
+ if (sum == NULL)
+ goto error;
+
+ for (i = oparg; i > 0; i--) {
+ PyObject *arg = PEEK(i);
if (PyDict_Update(sum, arg) < 0) {
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Format(PyExc_TypeError,
@@ -2716,7 +2729,62 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
}
- while (num_maps--)
+ while (oparg--)
+ Py_DECREF(POP());
+ PUSH(sum);
+ DISPATCH();
+ }
+
+ TARGET(BUILD_MAP_UNPACK_WITH_CALL) {
+ Py_ssize_t i;
+ PyObject *sum = PyDict_New();
+ if (sum == NULL)
+ goto error;
+
+ for (i = oparg; i > 0; i--) {
+ PyObject *arg = PEEK(i);
+ if (_PyDict_MergeEx(sum, arg, 2) < 0) {
+ PyObject *func = PEEK(2 + oparg);
+ if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%.200s argument after ** "
+ "must be a mapping, not %.200s",
+ PyEval_GetFuncName(func),
+ PyEval_GetFuncDesc(func),
+ arg->ob_type->tp_name);
+ }
+ else if (PyErr_ExceptionMatches(PyExc_KeyError)) {
+ PyObject *exc, *val, *tb;
+ PyErr_Fetch(&exc, &val, &tb);
+ if (val && PyTuple_Check(val) && PyTuple_GET_SIZE(val) == 1) {
+ PyObject *key = PyTuple_GET_ITEM(val, 0);
+ if (!PyUnicode_Check(key)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%.200s keywords must be strings",
+ PyEval_GetFuncName(func),
+ PyEval_GetFuncDesc(func));
+ } else {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%.200s got multiple "
+ "values for keyword argument '%U'",
+ PyEval_GetFuncName(func),
+ PyEval_GetFuncDesc(func),
+ key);
+ }
+ Py_XDECREF(exc);
+ Py_XDECREF(val);
+ Py_XDECREF(tb);
+ }
+ else {
+ PyErr_Restore(exc, val, tb);
+ }
+ }
+ Py_DECREF(sum);
+ goto error;
+ }
+ }
+
+ while (oparg--)
Py_DECREF(POP());
PUSH(sum);
DISPATCH();
@@ -2765,45 +2833,13 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
}
TARGET(IMPORT_NAME) {
- _Py_IDENTIFIER(__import__);
PyObject *name = GETITEM(names, oparg);
- PyObject *func = _PyDict_GetItemId(f->f_builtins, &PyId___import__);
- PyObject *from, *level, *args, *res;
- if (func == NULL) {
- PyErr_SetString(PyExc_ImportError,
- "__import__ not found");
- goto error;
- }
- Py_INCREF(func);
- from = POP();
- level = TOP();
- if (PyLong_AsLong(level) != -1 || PyErr_Occurred())
- args = PyTuple_Pack(5,
- name,
- f->f_globals,
- f->f_locals == NULL ?
- Py_None : f->f_locals,
- from,
- level);
- else
- args = PyTuple_Pack(4,
- name,
- f->f_globals,
- f->f_locals == NULL ?
- Py_None : f->f_locals,
- from);
+ PyObject *fromlist = POP();
+ PyObject *level = TOP();
+ PyObject *res;
+ res = import_name(f, name, fromlist, level);
Py_DECREF(level);
- Py_DECREF(from);
- if (args == NULL) {
- Py_DECREF(func);
- STACKADJ(-1);
- goto error;
- }
- READ_TIMESTAMP(intr0);
- res = PyEval_CallObject(func, args);
- READ_TIMESTAMP(intr1);
- Py_DECREF(args);
- Py_DECREF(func);
+ Py_DECREF(fromlist);
SET_TOP(res);
if (res == NULL)
goto error;
@@ -2822,9 +2858,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
"no locals found during 'import *'");
goto error;
}
- READ_TIMESTAMP(intr0);
err = import_all_from(locals, from);
- READ_TIMESTAMP(intr1);
PyFrame_LocalsToFast(f, 0);
Py_DECREF(from);
if (err != 0)
@@ -2836,9 +2870,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
PyObject *name = GETITEM(names, oparg);
PyObject *from = TOP();
PyObject *res;
- READ_TIMESTAMP(intr0);
res = import_from(from, name);
- READ_TIMESTAMP(intr1);
PUSH(res);
if (res == NULL)
goto error;
@@ -2850,7 +2882,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
FAST_DISPATCH();
}
- PREDICTED_WITH_ARG(POP_JUMP_IF_FALSE);
+ PREDICTED(POP_JUMP_IF_FALSE);
TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
int err;
@@ -2874,7 +2906,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
- PREDICTED_WITH_ARG(POP_JUMP_IF_TRUE);
+ PREDICTED(POP_JUMP_IF_TRUE);
TARGET(POP_JUMP_IF_TRUE) {
PyObject *cond = POP();
int err;
@@ -2951,7 +2983,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
- PREDICTED_WITH_ARG(JUMP_ABSOLUTE);
+ PREDICTED(JUMP_ABSOLUTE);
TARGET(JUMP_ABSOLUTE) {
JUMPTO(oparg);
#if FAST_LOOPS
@@ -2977,6 +3009,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
if (iter == NULL)
goto error;
PREDICT(FOR_ITER);
+ PREDICT(CALL_FUNCTION);
DISPATCH();
}
@@ -3005,10 +3038,11 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
if (iter == NULL)
goto error;
}
+ PREDICT(LOAD_CONST);
DISPATCH();
}
- PREDICTED_WITH_ARG(FOR_ITER);
+ PREDICTED(FOR_ITER);
TARGET(FOR_ITER) {
/* before: [iter]; after: [iter, iter()] *or* [] */
PyObject *iter = TOP();
@@ -3030,6 +3064,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
STACKADJ(-1);
Py_DECREF(iter);
JUMPBY(oparg);
+ PREDICT(POP_BLOCK);
DISPATCH();
}
@@ -3046,10 +3081,9 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
goto fast_block_end;
}
- TARGET_WITH_IMPL(SETUP_LOOP, _setup_finally)
- TARGET_WITH_IMPL(SETUP_EXCEPT, _setup_finally)
- TARGET(SETUP_FINALLY)
- _setup_finally: {
+ TARGET(SETUP_LOOP)
+ TARGET(SETUP_EXCEPT)
+ TARGET(SETUP_FINALLY) {
/* NOTE: If you add any new block-setup opcodes that
are not try/except/finally handlers, you may need
to update the PyGen_NeedsFinalizing() function.
@@ -3080,6 +3114,7 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
if (res == NULL)
goto error;
PUSH(res);
+ PREDICT(GET_AWAITABLE);
DISPATCH();
}
@@ -3228,178 +3263,135 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
DISPATCH();
}
+ PREDICTED(CALL_FUNCTION);
TARGET(CALL_FUNCTION) {
PyObject **sp, *res;
PCALL(PCALL_ALL);
sp = stack_pointer;
-#ifdef WITH_TSC
- res = call_function(&sp, oparg, &intr0, &intr1);
-#else
- res = call_function(&sp, oparg);
-#endif
+ res = call_function(&sp, oparg, NULL);
stack_pointer = sp;
PUSH(res);
- if (res == NULL)
+ if (res == NULL) {
goto error;
+ }
DISPATCH();
}
- TARGET_WITH_IMPL(CALL_FUNCTION_VAR, _call_function_var_kw)
- TARGET_WITH_IMPL(CALL_FUNCTION_KW, _call_function_var_kw)
- TARGET(CALL_FUNCTION_VAR_KW)
- _call_function_var_kw: {
- int na = oparg & 0xff;
- int nk = (oparg>>8) & 0xff;
- int flags = (opcode - CALL_FUNCTION) & 3;
- int n = na + 2 * nk;
- PyObject **pfunc, *func, **sp, *res;
+ TARGET(CALL_FUNCTION_KW) {
+ PyObject **sp, *res, *names;
+
+ names = POP();
+ assert(PyTuple_CheckExact(names) && PyTuple_GET_SIZE(names) <= oparg);
PCALL(PCALL_ALL);
- if (flags & CALL_FLAG_VAR)
- n++;
- if (flags & CALL_FLAG_KW)
- n++;
- pfunc = stack_pointer - n - 1;
- func = *pfunc;
-
- if (PyMethod_Check(func)
- && PyMethod_GET_SELF(func) != NULL) {
- PyObject *self = PyMethod_GET_SELF(func);
- Py_INCREF(self);
- func = PyMethod_GET_FUNCTION(func);
- Py_INCREF(func);
- Py_SETREF(*pfunc, self);
- na++;
- /* n++; */
- } else
- Py_INCREF(func);
sp = stack_pointer;
- READ_TIMESTAMP(intr0);
- res = ext_do_call(func, &sp, flags, na, nk);
- READ_TIMESTAMP(intr1);
+ res = call_function(&sp, oparg, names);
stack_pointer = sp;
- Py_DECREF(func);
-
- while (stack_pointer > pfunc) {
- PyObject *o = POP();
- Py_DECREF(o);
- }
PUSH(res);
- if (res == NULL)
- goto error;
- DISPATCH();
- }
+ Py_DECREF(names);
- TARGET_WITH_IMPL(MAKE_CLOSURE, _make_function)
- TARGET(MAKE_FUNCTION)
- _make_function: {
- int posdefaults = oparg & 0xff;
- int kwdefaults = (oparg>>8) & 0xff;
- int num_annotations = (oparg >> 16) & 0x7fff;
-
- PyObject *qualname = POP(); /* qualname */
- PyObject *code = POP(); /* code object */
- PyObject *func = PyFunction_NewWithQualName(code, f->f_globals, qualname);
- Py_DECREF(code);
- Py_DECREF(qualname);
-
- if (func == NULL)
+ if (res == NULL) {
goto error;
-
- if (opcode == MAKE_CLOSURE) {
- PyObject *closure = POP();
- if (PyFunction_SetClosure(func, closure) != 0) {
- /* Can't happen unless bytecode is corrupt. */
- Py_DECREF(func);
- Py_DECREF(closure);
- goto error;
- }
- Py_DECREF(closure);
}
+ DISPATCH();
+ }
- if (num_annotations > 0) {
- Py_ssize_t name_ix;
- PyObject *names = POP(); /* names of args with annotations */
- PyObject *anns = PyDict_New();
- if (anns == NULL) {
- Py_DECREF(func);
- Py_DECREF(names);
- goto error;
- }
- name_ix = PyTuple_Size(names);
- assert(num_annotations == name_ix+1);
- while (name_ix > 0) {
- PyObject *name, *value;
- int err;
- --name_ix;
- name = PyTuple_GET_ITEM(names, name_ix);
- value = POP();
- err = PyDict_SetItem(anns, name, value);
- Py_DECREF(value);
- if (err != 0) {
- Py_DECREF(anns);
- Py_DECREF(func);
- Py_DECREF(names);
+ TARGET(CALL_FUNCTION_EX) {
+ PyObject *func, *callargs, *kwargs = NULL, *result;
+ PCALL(PCALL_ALL);
+ if (oparg & 0x01) {
+ kwargs = POP();
+ if (!PyDict_CheckExact(kwargs)) {
+ PyObject *d = PyDict_New();
+ if (d == NULL)
goto error;
- }
- }
- Py_DECREF(names);
-
- if (PyFunction_SetAnnotations(func, anns) != 0) {
- /* Can't happen unless
- PyFunction_SetAnnotations changes. */
- Py_DECREF(anns);
- Py_DECREF(func);
- goto error;
- }
- Py_DECREF(anns);
- }
-
- /* XXX Maybe this should be a separate opcode? */
- if (kwdefaults > 0) {
- PyObject *defs = PyDict_New();
- if (defs == NULL) {
- Py_DECREF(func);
- goto error;
- }
- while (--kwdefaults >= 0) {
- PyObject *v = POP(); /* default value */
- PyObject *key = POP(); /* kw only arg name */
- int err = PyDict_SetItem(defs, key, v);
- Py_DECREF(v);
- Py_DECREF(key);
- if (err != 0) {
- Py_DECREF(defs);
- Py_DECREF(func);
+ if (PyDict_Update(d, kwargs) != 0) {
+ Py_DECREF(d);
+ /* PyDict_Update raises attribute
+ * error (percolated from an attempt
+ * to get 'keys' attribute) instead of
+ * a type error if its second argument
+ * is not a mapping.
+ */
+ if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ func = SECOND();
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%.200s argument after ** "
+ "must be a mapping, not %.200s",
+ PyEval_GetFuncName(func),
+ PyEval_GetFuncDesc(func),
+ kwargs->ob_type->tp_name);
+ }
+ Py_DECREF(kwargs);
goto error;
}
+ Py_DECREF(kwargs);
+ kwargs = d;
}
- if (PyFunction_SetKwDefaults(func, defs) != 0) {
- /* Can't happen unless
- PyFunction_SetKwDefaults changes. */
- Py_DECREF(func);
- Py_DECREF(defs);
- goto error;
- }
- Py_DECREF(defs);
+ assert(PyDict_CheckExact(kwargs));
}
- if (posdefaults > 0) {
- PyObject *defs = PyTuple_New(posdefaults);
- if (defs == NULL) {
- Py_DECREF(func);
+ callargs = POP();
+ func = TOP();
+ if (!PyTuple_CheckExact(callargs)) {
+ if (Py_TYPE(callargs)->tp_iter == NULL &&
+ !PySequence_Check(callargs)) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%.200s argument after * "
+ "must be an iterable, not %.200s",
+ PyEval_GetFuncName(func),
+ PyEval_GetFuncDesc(func),
+ callargs->ob_type->tp_name);
+ Py_DECREF(callargs);
goto error;
}
- while (--posdefaults >= 0)
- PyTuple_SET_ITEM(defs, posdefaults, POP());
- if (PyFunction_SetDefaults(func, defs) != 0) {
- /* Can't happen unless
- PyFunction_SetDefaults changes. */
- Py_DECREF(defs);
- Py_DECREF(func);
+ Py_SETREF(callargs, PySequence_Tuple(callargs));
+ if (callargs == NULL) {
goto error;
}
- Py_DECREF(defs);
}
- PUSH(func);
+ assert(PyTuple_CheckExact(callargs));
+
+ result = do_call_core(func, callargs, kwargs);
+ Py_DECREF(func);
+ Py_DECREF(callargs);
+ Py_XDECREF(kwargs);
+
+ SET_TOP(result);
+ if (result == NULL) {
+ goto error;
+ }
+ DISPATCH();
+ }
+
+ TARGET(MAKE_FUNCTION) {
+ PyObject *qualname = POP();
+ PyObject *codeobj = POP();
+ PyFunctionObject *func = (PyFunctionObject *)
+ PyFunction_NewWithQualName(codeobj, f->f_globals, qualname);
+
+ Py_DECREF(codeobj);
+ Py_DECREF(qualname);
+ if (func == NULL) {
+ goto error;
+ }
+
+ if (oparg & 0x08) {
+ assert(PyTuple_CheckExact(TOP()));
+ func ->func_closure = POP();
+ }
+ if (oparg & 0x04) {
+ assert(PyDict_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();
}
@@ -3421,9 +3413,68 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
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_STR: conv_fn = PyObject_Str; break;
+ case FVC_REPR: conv_fn = PyObject_Repr; break;
+ case FVC_ASCII: conv_fn = PyObject_ASCII; break;
+
+ /* Must be 0 (meaning no conversion), since only four
+ values are allowed by (oparg & FVC_MASK). */
+ default: conv_fn = NULL; break;
+ }
+
+ /* 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(EXTENDED_ARG) {
- opcode = NEXTOP();
- oparg = oparg<<16 | NEXTARG();
+ int oldoparg = oparg;
+ NEXTOPARG();
+ oparg |= oldoparg << 8;
goto dispatch_opcode;
}
@@ -3450,7 +3501,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
assert(0);
error:
- READ_TIMESTAMP(inst1);
assert(why == WHY_NOT);
why = WHY_EXCEPTION;
@@ -3554,7 +3604,6 @@ fast_block_end:
if (why != WHY_NOT)
break;
- READ_TIMESTAMP(loop1);
assert(!PyErr_Occurred());
@@ -3573,7 +3622,7 @@ fast_block_end:
assert((retval != NULL) ^ (PyErr_Occurred() != NULL));
fast_yield:
- if (co->co_flags & (CO_GENERATOR | CO_COROUTINE)) {
+ if (co->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
/* The purpose of this block is to put aside the generator's exception
state and restore that of the calling frame. If the current
@@ -3584,9 +3633,11 @@ fast_yield:
state came into existence in this frame. (An uncaught exception
would have why == WHY_EXCEPTION, and we wouldn't be here). */
int i;
- for (i = 0; i < f->f_iblock; i++)
- if (f->f_blockstack[i].b_type == EXCEPT_HANDLER)
+ for (i = 0; i < f->f_iblock; i++) {
+ if (f->f_blockstack[i].b_type == EXCEPT_HANDLER) {
break;
+ }
+ }
if (i == f->f_iblock)
/* We did not create this exception. */
restore_and_clear_exc_state(tstate, f);
@@ -3627,6 +3678,8 @@ fast_yield:
/* pop frame */
exit_eval_frame:
+ if (PyDTrace_FUNCTION_RETURN_ENABLED())
+ dtrace_function_return(f);
Py_LeaveRecursiveCall();
f->f_executing = 0;
tstate->frame = f->f_back;
@@ -3697,12 +3750,12 @@ format_missing(const char *kind, PyCodeObject *co, PyObject *names)
}
static void
-missing_arguments(PyCodeObject *co, int missing, int defcount,
+missing_arguments(PyCodeObject *co, Py_ssize_t missing, Py_ssize_t defcount,
PyObject **fastlocals)
{
- int i, j = 0;
- int start, end;
- int positional = defcount != -1;
+ Py_ssize_t i, j = 0;
+ Py_ssize_t start, end;
+ int positional = (defcount != -1);
const char *kind = positional ? "positional" : "keyword-only";
PyObject *missing_names;
@@ -3735,33 +3788,39 @@ missing_arguments(PyCodeObject *co, int missing, int defcount,
}
static void
-too_many_positional(PyCodeObject *co, int given, int defcount, PyObject **fastlocals)
+too_many_positional(PyCodeObject *co, Py_ssize_t given, Py_ssize_t defcount,
+ PyObject **fastlocals)
{
int plural;
- int kwonly_given = 0;
- int i;
+ Py_ssize_t kwonly_given = 0;
+ Py_ssize_t i;
PyObject *sig, *kwonly_sig;
+ Py_ssize_t co_argcount = co->co_argcount;
assert((co->co_flags & CO_VARARGS) == 0);
/* Count missing keyword-only args. */
- for (i = co->co_argcount; i < co->co_argcount + co->co_kwonlyargcount; i++)
- if (GETLOCAL(i) != NULL)
+ for (i = co_argcount; i < co_argcount + co->co_kwonlyargcount; i++) {
+ if (GETLOCAL(i) != NULL) {
kwonly_given++;
+ }
+ }
if (defcount) {
- int atleast = co->co_argcount - defcount;
+ Py_ssize_t atleast = co_argcount - defcount;
plural = 1;
- sig = PyUnicode_FromFormat("from %d to %d", atleast, co->co_argcount);
+ sig = PyUnicode_FromFormat("from %zd to %zd", atleast, co_argcount);
}
else {
- plural = co->co_argcount != 1;
- sig = PyUnicode_FromFormat("%d", co->co_argcount);
+ plural = (co_argcount != 1);
+ sig = PyUnicode_FromFormat("%zd", co_argcount);
}
if (sig == NULL)
return;
if (kwonly_given) {
- const char *format = " positional argument%s (and %d keyword-only argument%s)";
- kwonly_sig = PyUnicode_FromFormat(format, given != 1 ? "s" : "", kwonly_given,
- kwonly_given != 1 ? "s" : "");
+ const char *format = " positional argument%s (and %zd keyword-only argument%s)";
+ kwonly_sig = PyUnicode_FromFormat(format,
+ given != 1 ? "s" : "",
+ kwonly_given,
+ kwonly_given != 1 ? "s" : "");
if (kwonly_sig == NULL) {
Py_DECREF(sig);
return;
@@ -3773,7 +3832,7 @@ too_many_positional(PyCodeObject *co, int given, int defcount, PyObject **fastlo
assert(kwonly_sig != NULL);
}
PyErr_Format(PyExc_TypeError,
- "%U() takes %U positional argument%s but %d%U %s given",
+ "%U() takes %U positional argument%s but %zd%U %s given",
co->co_name,
sig,
plural ? "s" : "",
@@ -3790,20 +3849,22 @@ too_many_positional(PyCodeObject *co, int given, int defcount, PyObject **fastlo
static PyObject *
_PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
- PyObject **args, int argcount, PyObject **kws, int kwcount,
- PyObject **defs, int defcount, PyObject *kwdefs, PyObject *closure,
+ PyObject **args, Py_ssize_t argcount,
+ PyObject **kwnames, PyObject **kwargs,
+ Py_ssize_t kwcount, int kwstep,
+ PyObject **defs, Py_ssize_t defcount,
+ PyObject *kwdefs, PyObject *closure,
PyObject *name, PyObject *qualname)
{
PyCodeObject* co = (PyCodeObject*)_co;
PyFrameObject *f;
PyObject *retval = NULL;
PyObject **fastlocals, **freevars;
- PyThreadState *tstate = PyThreadState_GET();
+ PyThreadState *tstate;
PyObject *x, *u;
- int total_args = co->co_argcount + co->co_kwonlyargcount;
- int i;
- int n = argcount;
- PyObject *kwdict = NULL;
+ const Py_ssize_t total_args = co->co_argcount + co->co_kwonlyargcount;
+ Py_ssize_t i, n;
+ PyObject *kwdict;
if (globals == NULL) {
PyErr_SetString(PyExc_SystemError,
@@ -3811,36 +3872,50 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
return NULL;
}
+ /* Create the frame */
+ tstate = PyThreadState_GET();
assert(tstate != NULL);
- assert(globals != NULL);
f = PyFrame_New(tstate, co, globals, locals);
- if (f == NULL)
+ if (f == NULL) {
return NULL;
-
+ }
fastlocals = f->f_localsplus;
freevars = f->f_localsplus + co->co_nlocals;
- /* Parse arguments. */
+ /* Create a dictionary for keyword parameters (**kwags) */
if (co->co_flags & CO_VARKEYWORDS) {
kwdict = PyDict_New();
if (kwdict == NULL)
goto fail;
i = total_args;
- if (co->co_flags & CO_VARARGS)
+ if (co->co_flags & CO_VARARGS) {
i++;
+ }
SETLOCAL(i, kwdict);
}
- if (argcount > co->co_argcount)
+ else {
+ kwdict = NULL;
+ }
+
+ /* Copy positional arguments into local variables */
+ if (argcount > co->co_argcount) {
n = co->co_argcount;
+ }
+ else {
+ n = argcount;
+ }
for (i = 0; i < n; i++) {
x = args[i];
Py_INCREF(x);
SETLOCAL(i, x);
}
+
+ /* Pack other positional arguments into the *args argument */
if (co->co_flags & CO_VARARGS) {
u = PyTuple_New(argcount - n);
- if (u == NULL)
+ if (u == NULL) {
goto fail;
+ }
SETLOCAL(total_args, u);
for (i = n; i < argcount; i++) {
x = args[i];
@@ -3848,69 +3923,82 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
PyTuple_SET_ITEM(u, i-n, x);
}
}
- for (i = 0; i < kwcount; i++) {
+
+ /* Handle keyword arguments passed as two strided arrays */
+ kwcount *= kwstep;
+ for (i = 0; i < kwcount; i += kwstep) {
PyObject **co_varnames;
- PyObject *keyword = kws[2*i];
- PyObject *value = kws[2*i + 1];
- int j;
+ PyObject *keyword = kwnames[i];
+ PyObject *value = kwargs[i];
+ Py_ssize_t j;
+
if (keyword == NULL || !PyUnicode_Check(keyword)) {
PyErr_Format(PyExc_TypeError,
"%U() keywords must be strings",
co->co_name);
goto fail;
}
+
/* Speed hack: do raw pointer compares. As names are
normally interned this should almost always hit. */
co_varnames = ((PyTupleObject *)(co->co_varnames))->ob_item;
for (j = 0; j < total_args; j++) {
- PyObject *nm = co_varnames[j];
- if (nm == keyword)
+ PyObject *name = co_varnames[j];
+ if (name == keyword) {
goto kw_found;
+ }
}
+
/* Slow fallback, just in case */
for (j = 0; j < total_args; j++) {
- PyObject *nm = co_varnames[j];
- int cmp = PyObject_RichCompareBool(
- keyword, nm, Py_EQ);
- if (cmp > 0)
+ PyObject *name = co_varnames[j];
+ int cmp = PyObject_RichCompareBool( keyword, name, Py_EQ);
+ if (cmp > 0) {
goto kw_found;
- else if (cmp < 0)
+ }
+ else if (cmp < 0) {
goto fail;
+ }
}
+
if (j >= total_args && kwdict == NULL) {
PyErr_Format(PyExc_TypeError,
- "%U() got an unexpected "
- "keyword argument '%S'",
- co->co_name,
- keyword);
+ "%U() got an unexpected keyword argument '%S'",
+ co->co_name, keyword);
goto fail;
}
+
if (PyDict_SetItem(kwdict, keyword, value) == -1) {
goto fail;
}
continue;
+
kw_found:
if (GETLOCAL(j) != NULL) {
PyErr_Format(PyExc_TypeError,
- "%U() got multiple "
- "values for argument '%S'",
- co->co_name,
- keyword);
+ "%U() got multiple values for argument '%S'",
+ co->co_name, keyword);
goto fail;
}
Py_INCREF(value);
SETLOCAL(j, value);
}
+
+ /* Check the number of positional arguments */
if (argcount > co->co_argcount && !(co->co_flags & CO_VARARGS)) {
too_many_positional(co, argcount, defcount, fastlocals);
goto fail;
}
+
+ /* Add missing positional arguments (copy default values from defs) */
if (argcount < co->co_argcount) {
- int m = co->co_argcount - defcount;
- int missing = 0;
- for (i = argcount; i < m; i++)
- if (GETLOCAL(i) == NULL)
+ Py_ssize_t m = co->co_argcount - defcount;
+ Py_ssize_t missing = 0;
+ for (i = argcount; i < m; i++) {
+ if (GETLOCAL(i) == NULL) {
missing++;
+ }
+ }
if (missing) {
missing_arguments(co, missing, defcount, fastlocals);
goto fail;
@@ -3927,8 +4015,10 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
}
}
}
+
+ /* Add missing keyword arguments (copy default values from kwdefs) */
if (co->co_kwonlyargcount > 0) {
- int missing = 0;
+ Py_ssize_t missing = 0;
for (i = co->co_argcount; i < total_args; i++) {
PyObject *name;
if (GETLOCAL(i) != NULL)
@@ -3969,13 +4059,16 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
goto fail;
SETLOCAL(co->co_nlocals + i, c);
}
+
+ /* Copy closure variables to free variables */
for (i = 0; i < PyTuple_GET_SIZE(co->co_freevars); ++i) {
PyObject *o = PyTuple_GET_ITEM(closure, i);
Py_INCREF(o);
freevars[PyTuple_GET_SIZE(co->co_cellvars) + i] = o;
}
- if (co->co_flags & (CO_GENERATOR | CO_COROUTINE)) {
+ /* Handle generator/coroutine/asynchronous generator */
+ if (co->co_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
PyObject *gen;
PyObject *coro_wrapper = tstate->coroutine_wrapper;
int is_coro = co->co_flags & CO_COROUTINE;
@@ -4000,6 +4093,8 @@ _PyEval_EvalCodeWithName(PyObject *_co, PyObject *globals, PyObject *locals,
* and return that as the value. */
if (is_coro) {
gen = PyCoro_New(f, name, qualname);
+ } else if (co->co_flags & CO_ASYNC_GENERATOR) {
+ gen = PyAsyncGen_New(f, name, qualname);
} else {
gen = PyGen_NewWithQualName(f, name, qualname);
}
@@ -4039,8 +4134,10 @@ PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals,
PyObject **defs, int defcount, PyObject *kwdefs, PyObject *closure)
{
return _PyEval_EvalCodeWithName(_co, globals, locals,
- args, argcount, kws, kwcount,
- defs, defcount, kwdefs, closure,
+ args, argcount,
+ kws, kws + 1, kwcount, 2,
+ defs, defcount,
+ kwdefs, closure,
NULL, NULL);
}
@@ -4299,7 +4396,7 @@ Error:
#ifdef LLTRACE
static int
-prtrace(PyObject *v, char *str)
+prtrace(PyObject *v, const char *str)
{
printf("%s ", str);
if (PyObject_Print(v, stdout, 0) != 0)
@@ -4476,6 +4573,38 @@ _PyEval_GetCoroutineWrapper(void)
return tstate->coroutine_wrapper;
}
+void
+_PyEval_SetAsyncGenFirstiter(PyObject *firstiter)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+
+ Py_XINCREF(firstiter);
+ Py_XSETREF(tstate->async_gen_firstiter, firstiter);
+}
+
+PyObject *
+_PyEval_GetAsyncGenFirstiter(void)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ return tstate->async_gen_firstiter;
+}
+
+void
+_PyEval_SetAsyncGenFinalizer(PyObject *finalizer)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+
+ Py_XINCREF(finalizer);
+ Py_XSETREF(tstate->async_gen_finalizer, finalizer);
+}
+
+PyObject *
+_PyEval_GetAsyncGenFinalizer(void)
+{
+ PyThreadState *tstate = PyThreadState_GET();
+ return tstate->async_gen_finalizer;
+}
+
PyObject *
PyEval_GetBuiltins(void)
{
@@ -4548,10 +4677,8 @@ PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
The arg must be a tuple or NULL. The kw must be a dict or NULL. */
PyObject *
-PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
+PyEval_CallObjectWithKeywords(PyObject *func, PyObject *args, PyObject *kwargs)
{
- PyObject *result;
-
#ifdef Py_DEBUG
/* PyEval_CallObjectWithKeywords() must not be called with an exception
set. It raises a new exception if parameters are invalid or if
@@ -4559,30 +4686,23 @@ PyEval_CallObjectWithKeywords(PyObject *func, PyObject *arg, PyObject *kw)
assert(!PyErr_Occurred());
#endif
- if (arg == NULL) {
- arg = PyTuple_New(0);
- if (arg == NULL)
- return NULL;
+ if (args == NULL) {
+ return _PyObject_FastCallDict(func, NULL, 0, kwargs);
}
- else if (!PyTuple_Check(arg)) {
+
+ if (!PyTuple_Check(args)) {
PyErr_SetString(PyExc_TypeError,
"argument list must be a tuple");
return NULL;
}
- else
- Py_INCREF(arg);
- if (kw != NULL && !PyDict_Check(kw)) {
+ if (kwargs != NULL && !PyDict_Check(kwargs)) {
PyErr_SetString(PyExc_TypeError,
"keyword list must be a dictionary");
- Py_DECREF(arg);
return NULL;
}
- result = PyObject_Call(func, arg, kw);
- Py_DECREF(arg);
-
- return result;
+ return PyObject_Call(func, args, kwargs);
}
const char *
@@ -4611,21 +4731,6 @@ PyEval_GetFuncDesc(PyObject *func)
return " object";
}
-static void
-err_args(PyObject *func, int flags, int nargs)
-{
- if (flags & METH_NOARGS)
- PyErr_Format(PyExc_TypeError,
- "%.200s() takes no arguments (%d given)",
- ((PyCFunctionObject *)func)->m_ml->ml_name,
- nargs);
- else
- PyErr_Format(PyExc_TypeError,
- "%.200s() takes exactly one argument (%d given)",
- ((PyCFunctionObject *)func)->m_ml->ml_name,
- nargs);
-}
-
#define C_TRACE(x, call) \
if (tstate->use_tracing && tstate->c_profilefunc) { \
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
@@ -4658,60 +4763,25 @@ if (tstate->use_tracing && tstate->c_profilefunc) { \
}
static PyObject *
-call_function(PyObject ***pp_stack, int oparg
-#ifdef WITH_TSC
- , uint64* pintr0, uint64* pintr1
-#endif
- )
+call_function(PyObject ***pp_stack, Py_ssize_t oparg, PyObject *kwnames)
{
- int na = oparg & 0xff;
- int nk = (oparg>>8) & 0xff;
- int n = na + 2 * nk;
- PyObject **pfunc = (*pp_stack) - n - 1;
+ PyObject **pfunc = (*pp_stack) - oparg - 1;
PyObject *func = *pfunc;
PyObject *x, *w;
+ Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
+ Py_ssize_t nargs = oparg - nkwargs;
+ PyObject **stack;
/* Always dispatch PyCFunction first, because these are
presumed to be the most frequent callable object.
*/
- if (PyCFunction_Check(func) && nk == 0) {
- int flags = PyCFunction_GET_FLAGS(func);
+ if (PyCFunction_Check(func)) {
PyThreadState *tstate = PyThreadState_GET();
PCALL(PCALL_CFUNCTION);
- if (flags & (METH_NOARGS | METH_O)) {
- PyCFunction meth = PyCFunction_GET_FUNCTION(func);
- PyObject *self = PyCFunction_GET_SELF(func);
- if (flags & METH_NOARGS && na == 0) {
- C_TRACE(x, (*meth)(self,NULL));
-
- x = _Py_CheckFunctionResult(func, x, NULL);
- }
- else if (flags & METH_O && na == 1) {
- PyObject *arg = EXT_POP(*pp_stack);
- C_TRACE(x, (*meth)(self,arg));
- Py_DECREF(arg);
- x = _Py_CheckFunctionResult(func, x, NULL);
- }
- else {
- err_args(func, flags, na);
- x = NULL;
- }
- }
- else {
- PyObject *callargs;
- callargs = load_args(pp_stack, na);
- if (callargs != NULL) {
- READ_TIMESTAMP(*pintr0);
- C_TRACE(x, PyCFunction_Call(func,callargs,NULL));
- READ_TIMESTAMP(*pintr1);
- Py_XDECREF(callargs);
- }
- else {
- x = NULL;
- }
- }
+ stack = (*pp_stack) - nargs - nkwargs;
+ C_TRACE(x, _PyCFunction_FastCallKeywords(func, stack, nargs, kwnames));
}
else {
if (PyMethod_Check(func) && PyMethod_GET_SELF(func) != NULL) {
@@ -4723,21 +4793,26 @@ call_function(PyObject ***pp_stack, int oparg
func = PyMethod_GET_FUNCTION(func);
Py_INCREF(func);
Py_SETREF(*pfunc, self);
- na++;
- n++;
- } else
+ nargs++;
+ }
+ else {
Py_INCREF(func);
- READ_TIMESTAMP(*pintr0);
- if (PyFunction_Check(func))
- x = fast_function(func, pp_stack, n, na, nk);
- else
- x = do_call(func, pp_stack, na, nk);
- READ_TIMESTAMP(*pintr1);
- Py_DECREF(func);
+ }
- assert((x != NULL) ^ (PyErr_Occurred() != NULL));
+ stack = (*pp_stack) - nargs - nkwargs;
+
+ if (PyFunction_Check(func)) {
+ x = fast_function(func, stack, nargs, kwnames);
+ }
+ else {
+ x = _PyObject_FastCallKeywords(func, stack, nargs, kwnames);
+ }
+
+ Py_DECREF(func);
}
+ assert((x != NULL) ^ (PyErr_Occurred() != NULL));
+
/* Clear the stack of the function object. Also removes
the arguments in case they weren't consumed already
(fast_function() and err_args() leave them on the stack).
@@ -4748,7 +4823,6 @@ call_function(PyObject ***pp_stack, int oparg
PCALL(PCALL_POP);
}
- assert((x != NULL) ^ (PyErr_Occurred() != NULL));
return x;
}
@@ -4761,257 +4835,197 @@ call_function(PyObject ***pp_stack, int oparg
done before evaluating the frame.
*/
+static PyObject*
+_PyFunction_FastCall(PyCodeObject *co, PyObject **args, Py_ssize_t nargs,
+ PyObject *globals)
+{
+ PyFrameObject *f;
+ PyThreadState *tstate = PyThreadState_GET();
+ PyObject **fastlocals;
+ Py_ssize_t i;
+ PyObject *result;
+
+ PCALL(PCALL_FASTER_FUNCTION);
+ assert(globals != NULL);
+ /* XXX Perhaps we should create a specialized
+ PyFrame_New() that doesn't take locals, but does
+ take builtins without sanity checking them.
+ */
+ assert(tstate != NULL);
+ f = PyFrame_New(tstate, co, globals, NULL);
+ if (f == NULL) {
+ return NULL;
+ }
+
+ fastlocals = f->f_localsplus;
+
+ for (i = 0; i < nargs; i++) {
+ Py_INCREF(*args);
+ fastlocals[i] = *args++;
+ }
+ result = PyEval_EvalFrameEx(f,0);
+
+ ++tstate->recursion_depth;
+ Py_DECREF(f);
+ --tstate->recursion_depth;
+
+ return result;
+}
+
static PyObject *
-fast_function(PyObject *func, PyObject ***pp_stack, int n, int na, int nk)
+fast_function(PyObject *func, PyObject **stack,
+ Py_ssize_t nargs, PyObject *kwnames)
{
PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
PyObject *globals = PyFunction_GET_GLOBALS(func);
PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
- PyObject *kwdefs = PyFunction_GET_KW_DEFAULTS(func);
- PyObject *name = ((PyFunctionObject *)func) -> func_name;
- PyObject *qualname = ((PyFunctionObject *)func) -> func_qualname;
- PyObject **d = NULL;
- int nd = 0;
+ PyObject *kwdefs, *closure, *name, *qualname;
+ PyObject **d;
+ Py_ssize_t nkwargs = (kwnames == NULL) ? 0 : PyTuple_GET_SIZE(kwnames);
+ Py_ssize_t nd;
+
+ assert(PyFunction_Check(func));
+ assert(nargs >= 0);
+ assert(kwnames == NULL || PyTuple_CheckExact(kwnames));
+ assert((nargs == 0 && nkwargs == 0) || stack != NULL);
+ /* kwnames must only contains str strings, no subclass, and all keys must
+ be unique */
PCALL(PCALL_FUNCTION);
PCALL(PCALL_FAST_FUNCTION);
- if (argdefs == NULL && co->co_argcount == n &&
- co->co_kwonlyargcount == 0 && nk==0 &&
- co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE)) {
- PyFrameObject *f;
- PyObject *retval = NULL;
- PyThreadState *tstate = PyThreadState_GET();
- PyObject **fastlocals, **stack;
- int i;
-
- PCALL(PCALL_FASTER_FUNCTION);
- assert(globals != NULL);
- /* XXX Perhaps we should create a specialized
- PyFrame_New() that doesn't take locals, but does
- take builtins without sanity checking them.
- */
- assert(tstate != NULL);
- f = PyFrame_New(tstate, co, globals, NULL);
- if (f == NULL)
- return NULL;
-
- fastlocals = f->f_localsplus;
- stack = (*pp_stack) - n;
- for (i = 0; i < n; i++) {
- Py_INCREF(*stack);
- fastlocals[i] = *stack++;
+ if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
+ co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
+ {
+ if (argdefs == NULL && co->co_argcount == nargs) {
+ return _PyFunction_FastCall(co, stack, nargs, globals);
+ }
+ else if (nargs == 0 && argdefs != NULL
+ && co->co_argcount == Py_SIZE(argdefs)) {
+ /* function called with no arguments, but all parameters have
+ a default value: use default values as arguments .*/
+ stack = &PyTuple_GET_ITEM(argdefs, 0);
+ return _PyFunction_FastCall(co, stack, Py_SIZE(argdefs), globals);
}
- retval = PyEval_EvalFrameEx(f,0);
- ++tstate->recursion_depth;
- Py_DECREF(f);
- --tstate->recursion_depth;
- return retval;
}
+
+ kwdefs = PyFunction_GET_KW_DEFAULTS(func);
+ closure = PyFunction_GET_CLOSURE(func);
+ name = ((PyFunctionObject *)func) -> func_name;
+ qualname = ((PyFunctionObject *)func) -> func_qualname;
+
if (argdefs != NULL) {
d = &PyTuple_GET_ITEM(argdefs, 0);
nd = Py_SIZE(argdefs);
}
- return _PyEval_EvalCodeWithName((PyObject*)co, globals,
- (PyObject *)NULL, (*pp_stack)-n, na,
- (*pp_stack)-2*nk, nk, d, nd, kwdefs,
- PyFunction_GET_CLOSURE(func),
- name, qualname);
+ else {
+ d = NULL;
+ nd = 0;
+ }
+ return _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
+ stack, nargs,
+ nkwargs ? &PyTuple_GET_ITEM(kwnames, 0) : NULL,
+ stack + nargs,
+ nkwargs, 1,
+ d, (int)nd, kwdefs,
+ closure, name, qualname);
}
-static PyObject *
-update_keyword_args(PyObject *orig_kwdict, int nk, PyObject ***pp_stack,
- PyObject *func)
+PyObject *
+_PyFunction_FastCallKeywords(PyObject *func, PyObject **stack,
+ Py_ssize_t nargs, PyObject *kwnames)
{
- PyObject *kwdict = NULL;
- if (orig_kwdict == NULL)
- kwdict = PyDict_New();
- else {
- kwdict = PyDict_Copy(orig_kwdict);
- Py_DECREF(orig_kwdict);
- }
- if (kwdict == NULL)
- return NULL;
- while (--nk >= 0) {
- int err;
- PyObject *value = EXT_POP(*pp_stack);
- PyObject *key = EXT_POP(*pp_stack);
- if (PyDict_GetItem(kwdict, key) != NULL) {
- PyErr_Format(PyExc_TypeError,
- "%.200s%s got multiple values "
- "for keyword argument '%U'",
- PyEval_GetFuncName(func),
- PyEval_GetFuncDesc(func),
- key);
- Py_DECREF(key);
- Py_DECREF(value);
- Py_DECREF(kwdict);
- return NULL;
- }
- err = PyDict_SetItem(kwdict, key, value);
- Py_DECREF(key);
- Py_DECREF(value);
- if (err) {
- Py_DECREF(kwdict);
- return NULL;
- }
- }
- return kwdict;
+ return fast_function(func, stack, nargs, kwnames);
}
-static PyObject *
-update_star_args(int nstack, int nstar, PyObject *stararg,
- PyObject ***pp_stack)
+PyObject *
+_PyFunction_FastCallDict(PyObject *func, PyObject **args, Py_ssize_t nargs,
+ PyObject *kwargs)
{
- PyObject *callargs, *w;
+ PyCodeObject *co = (PyCodeObject *)PyFunction_GET_CODE(func);
+ PyObject *globals = PyFunction_GET_GLOBALS(func);
+ PyObject *argdefs = PyFunction_GET_DEFAULTS(func);
+ PyObject *kwdefs, *closure, *name, *qualname;
+ PyObject *kwtuple, **k;
+ PyObject **d;
+ Py_ssize_t nd, nk;
+ PyObject *result;
- callargs = PyTuple_New(nstack + nstar);
- if (callargs == NULL) {
- return NULL;
- }
- if (nstar) {
- int i;
- for (i = 0; i < nstar; i++) {
- PyObject *a = PyTuple_GET_ITEM(stararg, i);
- Py_INCREF(a);
- PyTuple_SET_ITEM(callargs, nstack + i, a);
+ assert(func != NULL);
+ assert(nargs >= 0);
+ assert(nargs == 0 || args != NULL);
+ assert(kwargs == NULL || PyDict_Check(kwargs));
+
+ PCALL(PCALL_FUNCTION);
+ PCALL(PCALL_FAST_FUNCTION);
+
+ if (co->co_kwonlyargcount == 0 &&
+ (kwargs == NULL || PyDict_Size(kwargs) == 0) &&
+ co->co_flags == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
+ {
+ /* Fast paths */
+ if (argdefs == NULL && co->co_argcount == nargs) {
+ return _PyFunction_FastCall(co, args, nargs, globals);
+ }
+ else if (nargs == 0 && argdefs != NULL
+ && co->co_argcount == Py_SIZE(argdefs)) {
+ /* function called with no arguments, but all parameters have
+ a default value: use default values as arguments .*/
+ args = &PyTuple_GET_ITEM(argdefs, 0);
+ return _PyFunction_FastCall(co, args, Py_SIZE(argdefs), globals);
}
}
- while (--nstack >= 0) {
- w = EXT_POP(*pp_stack);
- PyTuple_SET_ITEM(callargs, nstack, w);
- }
- return callargs;
-}
-static PyObject *
-load_args(PyObject ***pp_stack, int na)
-{
- PyObject *args = PyTuple_New(na);
- PyObject *w;
+ if (kwargs != NULL) {
+ Py_ssize_t pos, i;
+ nk = PyDict_Size(kwargs);
- if (args == NULL)
- return NULL;
- while (--na >= 0) {
- w = EXT_POP(*pp_stack);
- PyTuple_SET_ITEM(args, na, w);
+ kwtuple = PyTuple_New(2 * nk);
+ if (kwtuple == NULL) {
+ return NULL;
+ }
+
+ k = &PyTuple_GET_ITEM(kwtuple, 0);
+ pos = i = 0;
+ while (PyDict_Next(kwargs, &pos, &k[i], &k[i+1])) {
+ Py_INCREF(k[i]);
+ Py_INCREF(k[i+1]);
+ i += 2;
+ }
+ nk = i / 2;
+ }
+ else {
+ kwtuple = NULL;
+ k = NULL;
+ nk = 0;
}
- return args;
-}
-static PyObject *
-do_call(PyObject *func, PyObject ***pp_stack, int na, int nk)
-{
- PyObject *callargs = NULL;
- PyObject *kwdict = NULL;
- PyObject *result = NULL;
+ kwdefs = PyFunction_GET_KW_DEFAULTS(func);
+ closure = PyFunction_GET_CLOSURE(func);
+ name = ((PyFunctionObject *)func) -> func_name;
+ qualname = ((PyFunctionObject *)func) -> func_qualname;
- if (nk > 0) {
- kwdict = update_keyword_args(NULL, nk, pp_stack, func);
- if (kwdict == NULL)
- goto call_fail;
+ if (argdefs != NULL) {
+ d = &PyTuple_GET_ITEM(argdefs, 0);
+ nd = Py_SIZE(argdefs);
}
- callargs = load_args(pp_stack, na);
- if (callargs == NULL)
- goto call_fail;
-#ifdef CALL_PROFILE
- /* At this point, we have to look at the type of func to
- update the call stats properly. Do it here so as to avoid
- exposing the call stats machinery outside ceval.c
- */
- if (PyFunction_Check(func))
- PCALL(PCALL_FUNCTION);
- else if (PyMethod_Check(func))
- PCALL(PCALL_METHOD);
- else if (PyType_Check(func))
- PCALL(PCALL_TYPE);
- else if (PyCFunction_Check(func))
- PCALL(PCALL_CFUNCTION);
- else
- PCALL(PCALL_OTHER);
-#endif
- if (PyCFunction_Check(func)) {
- PyThreadState *tstate = PyThreadState_GET();
- C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
+ else {
+ d = NULL;
+ nd = 0;
}
- else
- result = PyObject_Call(func, callargs, kwdict);
-call_fail:
- Py_XDECREF(callargs);
- Py_XDECREF(kwdict);
+
+ result = _PyEval_EvalCodeWithName((PyObject*)co, globals, (PyObject *)NULL,
+ args, nargs,
+ k, k + 1, nk, 2,
+ d, nd, kwdefs,
+ closure, name, qualname);
+ Py_XDECREF(kwtuple);
return result;
}
static PyObject *
-ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
+do_call_core(PyObject *func, PyObject *callargs, PyObject *kwdict)
{
- int nstar = 0;
- PyObject *callargs = NULL;
- PyObject *stararg = NULL;
- PyObject *kwdict = NULL;
- PyObject *result = NULL;
-
- if (flags & CALL_FLAG_KW) {
- kwdict = EXT_POP(*pp_stack);
- if (!PyDict_Check(kwdict)) {
- PyObject *d;
- d = PyDict_New();
- if (d == NULL)
- goto ext_call_fail;
- if (PyDict_Update(d, kwdict) != 0) {
- Py_DECREF(d);
- /* PyDict_Update raises attribute
- * error (percolated from an attempt
- * to get 'keys' attribute) instead of
- * a type error if its second argument
- * is not a mapping.
- */
- if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
- PyErr_Format(PyExc_TypeError,
- "%.200s%.200s argument after ** "
- "must be a mapping, not %.200s",
- PyEval_GetFuncName(func),
- PyEval_GetFuncDesc(func),
- kwdict->ob_type->tp_name);
- }
- goto ext_call_fail;
- }
- Py_DECREF(kwdict);
- kwdict = d;
- }
- }
- if (nk > 0) {
- kwdict = update_keyword_args(kwdict, nk, pp_stack, func);
- if (kwdict == NULL)
- goto ext_call_fail;
- }
-
- if (flags & CALL_FLAG_VAR) {
- stararg = EXT_POP(*pp_stack);
- if (!PyTuple_Check(stararg)) {
- PyObject *t = NULL;
- if (Py_TYPE(stararg)->tp_iter == NULL &&
- !PySequence_Check(stararg)) {
- PyErr_Format(PyExc_TypeError,
- "%.200s%.200s argument after * "
- "must be an iterable, not %.200s",
- PyEval_GetFuncName(func),
- PyEval_GetFuncDesc(func),
- stararg->ob_type->tp_name);
- goto ext_call_fail;
- }
- t = PySequence_Tuple(stararg);
- if (t == NULL) {
- goto ext_call_fail;
- }
- Py_DECREF(stararg);
- stararg = t;
- }
- nstar = PyTuple_GET_SIZE(stararg);
- }
- callargs = update_star_args(na, nstar, stararg, pp_stack);
- if (callargs == NULL)
- goto ext_call_fail;
#ifdef CALL_PROFILE
/* At this point, we have to look at the type of func to
update the call stats properly. Do it here so as to avoid
@@ -5028,17 +5042,16 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
else
PCALL(PCALL_OTHER);
#endif
+
if (PyCFunction_Check(func)) {
+ PyObject *result;
PyThreadState *tstate = PyThreadState_GET();
C_TRACE(result, PyCFunction_Call(func, callargs, kwdict));
+ return result;
+ }
+ else {
+ return PyObject_Call(func, callargs, kwdict);
}
- else
- result = PyObject_Call(func, callargs, kwdict);
-ext_call_fail:
- Py_XDECREF(callargs);
- Py_XDECREF(kwdict);
- Py_XDECREF(stararg);
- return result;
}
/* Extract a slice index from a PyLong or an object with the
@@ -5128,6 +5141,46 @@ cmp_outcome(int op, PyObject *v, PyObject *w)
}
static PyObject *
+import_name(PyFrameObject *f, PyObject *name, PyObject *fromlist, PyObject *level)
+{
+ _Py_IDENTIFIER(__import__);
+ PyObject *import_func, *res;
+ PyObject* stack[5];
+
+ import_func = _PyDict_GetItemId(f->f_builtins, &PyId___import__);
+ if (import_func == NULL) {
+ PyErr_SetString(PyExc_ImportError, "__import__ not found");
+ return NULL;
+ }
+
+ /* Fast path for not overloaded __import__. */
+ if (import_func == PyThreadState_GET()->interp->import_func) {
+ int ilevel = _PyLong_AsInt(level);
+ if (ilevel == -1 && PyErr_Occurred()) {
+ return NULL;
+ }
+ res = PyImport_ImportModuleLevelObject(
+ name,
+ f->f_globals,
+ f->f_locals == NULL ? Py_None : f->f_locals,
+ fromlist,
+ ilevel);
+ return res;
+ }
+
+ Py_INCREF(import_func);
+
+ stack[0] = name;
+ stack[1] = f->f_globals;
+ stack[2] = f->f_locals == NULL ? Py_None : f->f_locals;
+ stack[3] = fromlist;
+ stack[4] = level;
+ res = _PyObject_FastCall(import_func, stack, 5);
+ Py_DECREF(import_func);
+ return res;
+}
+
+static PyObject *
import_from(PyObject *v, PyObject *name)
{
PyObject *x;
@@ -5263,7 +5316,7 @@ format_exc_unbound(PyCodeObject *co, int oparg)
static PyObject *
unicode_concatenate(PyObject *v, PyObject *w,
- PyFrameObject *f, unsigned char *next_instr)
+ PyFrameObject *f, const _Py_CODEUNIT *next_instr)
{
PyObject *res;
if (Py_REFCNT(v) == 2) {
@@ -5273,10 +5326,11 @@ unicode_concatenate(PyObject *v, PyObject *w,
* 'variable'. We try to delete the variable now to reduce
* the refcnt to 1.
*/
- switch (*next_instr) {
+ int opcode, oparg;
+ NEXTOPARG();
+ switch (opcode) {
case STORE_FAST:
{
- int oparg = PEEKARG();
PyObject **fastlocals = f->f_localsplus;
if (GETLOCAL(oparg) == v)
SETLOCAL(oparg, NULL);
@@ -5286,7 +5340,7 @@ unicode_concatenate(PyObject *v, PyObject *w,
{
PyObject **freevars = (f->f_localsplus +
f->f_code->co_nlocals);
- PyObject *c = freevars[PEEKARG()];
+ PyObject *c = freevars[oparg];
if (PyCell_GET(c) == v)
PyCell_Set(c, NULL);
break;
@@ -5294,7 +5348,7 @@ unicode_concatenate(PyObject *v, PyObject *w,
case STORE_NAME:
{
PyObject *names = f->f_code->co_names;
- PyObject *name = GETITEM(names, PEEKARG());
+ PyObject *name = GETITEM(names, oparg);
PyObject *locals = f->f_locals;
if (PyDict_CheckExact(locals) &&
PyDict_GetItem(locals, name) == v) {
@@ -5354,3 +5408,79 @@ _Py_GetDXProfile(PyObject *self, PyObject *args)
}
#endif
+
+Py_ssize_t
+_PyEval_RequestCodeExtraIndex(freefunc free)
+{
+ PyThreadState *tstate = PyThreadState_Get();
+ Py_ssize_t new_index;
+
+ if (tstate->co_extra_user_count == MAX_CO_EXTRA_USERS - 1) {
+ return -1;
+ }
+ new_index = tstate->co_extra_user_count++;
+ tstate->co_extra_freefuncs[new_index] = free;
+ return new_index;
+}
+
+static void
+dtrace_function_entry(PyFrameObject *f)
+{
+ char* filename;
+ char* funcname;
+ int lineno;
+
+ filename = PyUnicode_AsUTF8(f->f_code->co_filename);
+ funcname = PyUnicode_AsUTF8(f->f_code->co_name);
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+
+ PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
+}
+
+static void
+dtrace_function_return(PyFrameObject *f)
+{
+ char* filename;
+ char* funcname;
+ int lineno;
+
+ filename = PyUnicode_AsUTF8(f->f_code->co_filename);
+ funcname = PyUnicode_AsUTF8(f->f_code->co_name);
+ lineno = PyCode_Addr2Line(f->f_code, f->f_lasti);
+
+ PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
+}
+
+/* DTrace equivalent of maybe_call_line_trace. */
+static void
+maybe_dtrace_line(PyFrameObject *frame,
+ int *instr_lb, int *instr_ub, int *instr_prev)
+{
+ int line = frame->f_lineno;
+ char *co_filename, *co_name;
+
+ /* If the last instruction executed isn't in the current
+ instruction window, reset the window.
+ */
+ if (frame->f_lasti < *instr_lb || frame->f_lasti >= *instr_ub) {
+ PyAddrPair bounds;
+ line = _PyCode_CheckLineNumber(frame->f_code, frame->f_lasti,
+ &bounds);
+ *instr_lb = bounds.ap_lower;
+ *instr_ub = bounds.ap_upper;
+ }
+ /* 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 call the trace function. */
+ if (frame->f_lasti == *instr_lb || frame->f_lasti < *instr_prev) {
+ frame->f_lineno = line;
+ 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);
+ }
+ *instr_prev = frame->f_lasti;
+}