mirror of
https://github.com/python/cpython.git
synced 2025-07-16 07:45:20 +00:00
bpo-46329: Streamline calling sequence a bit. (GH-31465)
* Move handling of bound-methods to PRECALL. * Remove call_shape.postcall_shrink * Remove call_shape.callable * Remove call_shape.callable. Change CALL oparg to match PRECALL oparg. * Move KW_NAMES before PRECALL. * Update opcode docs in dis.rst
This commit is contained in:
parent
0a222db2bc
commit
59585d6b2e
7 changed files with 218 additions and 178 deletions
269
Python/ceval.c
269
Python/ceval.c
|
@ -1585,15 +1585,19 @@ pop_frame(PyThreadState *tstate, InterpreterFrame *frame)
|
|||
}
|
||||
|
||||
/* It is only between the PRECALL instruction and the following CALL,
|
||||
* that these values have any meaning.
|
||||
* that this has any meaning.
|
||||
*/
|
||||
typedef struct {
|
||||
PyObject *callable;
|
||||
PyObject *kwnames;
|
||||
int total_args;
|
||||
int postcall_shrink;
|
||||
} CallShape;
|
||||
|
||||
static inline bool
|
||||
is_method(PyObject **stack_pointer, int args) {
|
||||
return PEEK(args+2) != NULL;
|
||||
}
|
||||
|
||||
#define KWNAMES_LEN() \
|
||||
(call_shape.kwnames == NULL ? 0 : ((int)PyTuple_GET_SIZE(call_shape.kwnames)))
|
||||
|
||||
PyObject* _Py_HOT_FUNCTION
|
||||
_PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int throwflag)
|
||||
|
@ -1616,11 +1620,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
|
|||
CFrame cframe;
|
||||
CallShape call_shape;
|
||||
call_shape.kwnames = NULL; // Borrowed reference. Reset by CALL instructions.
|
||||
/* The following three values are always set by the PRECALL instructions.
|
||||
They are set here to keep the compiler happy. */
|
||||
call_shape.postcall_shrink = 0;
|
||||
call_shape.total_args = 0;
|
||||
call_shape.callable = NULL; // Strong reference
|
||||
|
||||
/* WARNING: Because the CFrame lives on the C stack,
|
||||
* but can be accessed from a heap allocated object (tstate)
|
||||
|
@ -4513,23 +4512,31 @@ handle_eval_breaker:
|
|||
int nargs = oparg + is_method;
|
||||
/* Move ownership of reference from stack to call_shape
|
||||
* and make sure that NULL is cleared from stack */
|
||||
call_shape.callable = PEEK(nargs + 1);
|
||||
call_shape.postcall_shrink = 2-is_method;
|
||||
|
||||
call_shape.total_args = nargs;
|
||||
assert(call_shape.kwnames == NULL);
|
||||
PyObject *function = PEEK(nargs + 1);
|
||||
#ifdef Py_STATS
|
||||
extern int _PySpecialization_ClassifyCallable(PyObject *);
|
||||
SpecializationStats *stats =
|
||||
&_py_stats.opcode_stats[PRECALL].specialization;
|
||||
stats->failure++;
|
||||
int kind = _PySpecialization_ClassifyCallable(call_shape.callable);
|
||||
int kind = _PySpecialization_ClassifyCallable(function);
|
||||
stats->failure_kinds[kind]++;
|
||||
#endif
|
||||
if (!is_method && 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);
|
||||
function = meth;
|
||||
}
|
||||
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(KW_NAMES) {
|
||||
assert(call_shape.kwnames == NULL);
|
||||
assert(oparg < PyTuple_GET_SIZE(consts));
|
||||
call_shape.kwnames = GETITEM(consts, oparg);
|
||||
DISPATCH();
|
||||
|
@ -4537,25 +4544,12 @@ handle_eval_breaker:
|
|||
|
||||
TARGET(CALL) {
|
||||
PREDICTED(CALL);
|
||||
PyObject *function;
|
||||
assert((oparg == 0 && call_shape.kwnames == NULL)
|
||||
|| (oparg != 0 && oparg == PyTuple_GET_SIZE(call_shape.kwnames)));
|
||||
int is_meth;
|
||||
call_function:
|
||||
function = call_shape.callable;
|
||||
if (Py_TYPE(function) == &PyMethod_Type) {
|
||||
PyObject *meth = ((PyMethodObject *)function)->im_func;
|
||||
PyObject *self = ((PyMethodObject *)function)->im_self;
|
||||
Py_INCREF(meth);
|
||||
Py_INCREF(self);
|
||||
PEEK(call_shape.total_args + 1) = self;
|
||||
Py_DECREF(function);
|
||||
function = meth;
|
||||
call_shape.total_args++;
|
||||
assert(call_shape.postcall_shrink >= 1);
|
||||
call_shape.postcall_shrink--;
|
||||
}
|
||||
int total_args = call_shape.total_args;
|
||||
int positional_args = total_args - oparg;
|
||||
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;
|
||||
|
@ -4566,7 +4560,7 @@ handle_eval_breaker:
|
|||
stack_pointer, positional_args, call_shape.kwnames
|
||||
);
|
||||
call_shape.kwnames = NULL;
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
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) {
|
||||
|
@ -4599,7 +4593,7 @@ handle_eval_breaker:
|
|||
for (int i = 0; i < total_args; i++) {
|
||||
Py_DECREF(stack_pointer[i]);
|
||||
}
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
PUSH(res);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
|
@ -4610,14 +4604,14 @@ handle_eval_breaker:
|
|||
|
||||
TARGET(CALL_ADAPTIVE) {
|
||||
SpecializedCacheEntry *cache = GET_CACHE();
|
||||
int named_args = cache->adaptive.original_oparg;
|
||||
assert((named_args == 0 && call_shape.kwnames == NULL)
|
||||
|| (named_args != 0 && named_args == PyTuple_GET_SIZE(call_shape.kwnames)));
|
||||
int original_oparg = cache->adaptive.original_oparg;
|
||||
if (cache->adaptive.counter == 0) {
|
||||
next_instr--;
|
||||
int nargs = call_shape.total_args;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int nargs = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(nargs + 1);
|
||||
int err = _Py_Specialize_CallNoKw(
|
||||
call_shape.callable, next_instr, nargs,
|
||||
callable, next_instr, nargs,
|
||||
call_shape.kwnames, cache, BUILTINS());
|
||||
if (err < 0) {
|
||||
goto error;
|
||||
|
@ -4627,7 +4621,7 @@ handle_eval_breaker:
|
|||
else {
|
||||
STAT_INC(CALL, deferred);
|
||||
cache->adaptive.counter--;
|
||||
oparg = named_args;
|
||||
oparg = original_oparg;
|
||||
goto call_function;
|
||||
}
|
||||
}
|
||||
|
@ -4635,10 +4629,13 @@ handle_eval_breaker:
|
|||
TARGET(CALL_PY_EXACT_ARGS) {
|
||||
assert(call_shape.kwnames == NULL);
|
||||
SpecializedCacheEntry *caches = GET_CACHE();
|
||||
int argcount = call_shape.total_args;
|
||||
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
|
||||
int original_oparg = caches->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int argcount = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(argcount + 1);
|
||||
DEOPT_IF(!PyFunction_Check(callable), CALL);
|
||||
_PyCallCache *cache1 = &caches[-1].call;
|
||||
PyFunctionObject *func = (PyFunctionObject *)call_shape.callable;
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
DEOPT_IF(func->func_version != cache1->func_version, CALL);
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(code->co_argcount != argcount, CALL);
|
||||
|
@ -4654,7 +4651,7 @@ handle_eval_breaker:
|
|||
for (int i = argcount; i < code->co_nlocalsplus; i++) {
|
||||
new_frame->localsplus[i] = NULL;
|
||||
}
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
new_frame->previous = frame;
|
||||
frame = cframe.current_frame = new_frame;
|
||||
|
@ -4664,10 +4661,13 @@ handle_eval_breaker:
|
|||
TARGET(CALL_PY_WITH_DEFAULTS) {
|
||||
assert(call_shape.kwnames == NULL);
|
||||
SpecializedCacheEntry *caches = GET_CACHE();
|
||||
int argcount = call_shape.total_args;
|
||||
DEOPT_IF(!PyFunction_Check(call_shape.callable), CALL);
|
||||
int original_oparg = caches->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int argcount = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(argcount + 1);
|
||||
DEOPT_IF(!PyFunction_Check(callable), CALL);
|
||||
_PyCallCache *cache1 = &caches[-1].call;
|
||||
PyFunctionObject *func = (PyFunctionObject *)call_shape.callable;
|
||||
PyFunctionObject *func = (PyFunctionObject *)callable;
|
||||
DEOPT_IF(func->func_version != cache1->func_version, CALL);
|
||||
PyCodeObject *code = (PyCodeObject *)func->func_code;
|
||||
DEOPT_IF(argcount > code->co_argcount, CALL);
|
||||
|
@ -4691,7 +4691,7 @@ handle_eval_breaker:
|
|||
for (int i = code->co_argcount; i < code->co_nlocalsplus; i++) {
|
||||
new_frame->localsplus[i] = NULL;
|
||||
}
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||
new_frame->previous = frame;
|
||||
frame = cframe.current_frame = new_frame;
|
||||
|
@ -4701,14 +4701,15 @@ handle_eval_breaker:
|
|||
TARGET(CALL_NO_KW_TYPE_1) {
|
||||
assert(call_shape.kwnames == NULL);
|
||||
assert(cframe.use_tracing == 0);
|
||||
DEOPT_IF(call_shape.total_args != 1, CALL);
|
||||
assert(GET_CACHE()->adaptive.original_oparg == 1);
|
||||
DEOPT_IF(is_method(stack_pointer, 1), CALL);
|
||||
PyObject *obj = TOP();
|
||||
PyObject *callable = SECOND();
|
||||
DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL);
|
||||
PyObject *res = Py_NewRef(Py_TYPE(obj));
|
||||
Py_DECREF(callable);
|
||||
Py_DECREF(obj);
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2);
|
||||
SET_TOP(res);
|
||||
NOTRACE_DISPATCH();
|
||||
}
|
||||
|
@ -4716,16 +4717,18 @@ handle_eval_breaker:
|
|||
TARGET(CALL_NO_KW_STR_1) {
|
||||
assert(call_shape.kwnames == NULL);
|
||||
assert(cframe.use_tracing == 0);
|
||||
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
|
||||
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
|
||||
DEOPT_IF(call_shape.total_args != 1, CALL);
|
||||
assert(GET_CACHE()->adaptive.original_oparg == 1);
|
||||
PyObject *callable = PEEK(2);
|
||||
DEOPT_IF(!PyType_Check(callable), CALL);
|
||||
PyTypeObject *tp = (PyTypeObject *)callable;
|
||||
DEOPT_IF(is_method(stack_pointer, 1), CALL);
|
||||
DEOPT_IF(tp != &PyUnicode_Type, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
PyObject *arg = TOP();
|
||||
PyObject *res = PyObject_Str(arg);
|
||||
Py_DECREF(arg);
|
||||
Py_DECREF(&PyUnicode_Type);
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2);
|
||||
SET_TOP(res);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
|
@ -4736,16 +4739,19 @@ handle_eval_breaker:
|
|||
|
||||
TARGET(CALL_NO_KW_TUPLE_1) {
|
||||
assert(call_shape.kwnames == NULL);
|
||||
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
|
||||
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
|
||||
DEOPT_IF(call_shape.total_args != 1, CALL);
|
||||
assert(GET_CACHE()->adaptive.original_oparg == 1);
|
||||
int is_meth = is_method(stack_pointer, 1);
|
||||
PyObject *callable = PEEK(2);
|
||||
DEOPT_IF(!PyType_Check(callable), CALL);
|
||||
PyTypeObject *tp = (PyTypeObject *)callable;
|
||||
DEOPT_IF(is_meth, CALL);
|
||||
DEOPT_IF(tp != &PyTuple_Type, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
PyObject *arg = TOP();
|
||||
PyObject *res = PySequence_Tuple(arg);
|
||||
Py_DECREF(arg);
|
||||
Py_DECREF(&PyTuple_Type);
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2);
|
||||
SET_TOP(res);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
|
@ -4755,22 +4761,25 @@ handle_eval_breaker:
|
|||
}
|
||||
|
||||
TARGET(CALL_BUILTIN_CLASS) {
|
||||
DEOPT_IF(!PyType_Check(call_shape.callable), CALL);
|
||||
PyTypeObject *tp = (PyTypeObject *)call_shape.callable;
|
||||
int original_oparg = GET_CACHE()->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
int kwnames_len = KWNAMES_LEN();
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
DEOPT_IF(!PyType_Check(callable), CALL);
|
||||
PyTypeObject *tp = (PyTypeObject *)callable;
|
||||
DEOPT_IF(tp->tp_vectorcall == NULL, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
int kwnames_len = GET_CACHE()->adaptive.original_oparg;
|
||||
|
||||
int nargs = call_shape.total_args - kwnames_len;
|
||||
STACK_SHRINK(call_shape.total_args);
|
||||
PyObject *res = tp->tp_vectorcall((PyObject *)tp, stack_pointer, nargs, call_shape.kwnames);
|
||||
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 < call_shape.total_args; i++) {
|
||||
for (int i = 0; i < total_args; i++) {
|
||||
Py_DECREF(stack_pointer[i]);
|
||||
}
|
||||
Py_DECREF(tp);
|
||||
STACK_SHRINK(call_shape.postcall_shrink-1);
|
||||
STACK_SHRINK(1-is_meth);
|
||||
SET_TOP(res);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
|
@ -4783,8 +4792,12 @@ handle_eval_breaker:
|
|||
assert(cframe.use_tracing == 0);
|
||||
/* Builtin METH_O functions */
|
||||
assert(call_shape.kwnames == NULL);
|
||||
DEOPT_IF(call_shape.total_args != 1, CALL);
|
||||
PyObject *callable = call_shape.callable;
|
||||
SpecializedCacheEntry *caches = GET_CACHE();
|
||||
int original_oparg = caches->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
DEOPT_IF(total_args != 1, CALL);
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
|
||||
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
|
@ -4802,7 +4815,7 @@ handle_eval_breaker:
|
|||
|
||||
Py_DECREF(arg);
|
||||
Py_DECREF(callable);
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
SET_TOP(res);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
|
@ -4815,27 +4828,30 @@ handle_eval_breaker:
|
|||
assert(cframe.use_tracing == 0);
|
||||
/* Builtin METH_FASTCALL functions, without keywords */
|
||||
assert(call_shape.kwnames == NULL);
|
||||
PyObject *callable = call_shape.callable;
|
||||
SpecializedCacheEntry *caches = GET_CACHE();
|
||||
int original_oparg = caches->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
|
||||
DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL,
|
||||
CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
|
||||
int nargs = call_shape.total_args;
|
||||
PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
|
||||
STACK_SHRINK(nargs);
|
||||
STACK_SHRINK(total_args);
|
||||
/* res = func(self, args, nargs) */
|
||||
PyObject *res = ((_PyCFunctionFast)(void(*)(void))cfunc)(
|
||||
PyCFunction_GET_SELF(callable),
|
||||
stack_pointer,
|
||||
nargs);
|
||||
total_args);
|
||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
|
||||
/* Free the arguments. */
|
||||
for (int i = 0; i < nargs; i++) {
|
||||
for (int i = 0; i < total_args; i++) {
|
||||
Py_DECREF(stack_pointer[i]);
|
||||
}
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
PUSH(res);
|
||||
Py_DECREF(callable);
|
||||
if (res == NULL) {
|
||||
|
@ -4853,19 +4869,16 @@ handle_eval_breaker:
|
|||
TARGET(CALL_BUILTIN_FAST_WITH_KEYWORDS) {
|
||||
assert(cframe.use_tracing == 0);
|
||||
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */
|
||||
PyObject *callable = call_shape.callable;
|
||||
SpecializedCacheEntry *caches = GET_CACHE();
|
||||
int original_oparg = caches->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
|
||||
DEOPT_IF(PyCFunction_GET_FLAGS(callable) !=
|
||||
(METH_FASTCALL | METH_KEYWORDS), CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
int kwnames_len = GET_CACHE()->adaptive.original_oparg;
|
||||
assert(
|
||||
(call_shape.kwnames == NULL && kwnames_len == 0) ||
|
||||
(call_shape.kwnames != NULL &&
|
||||
PyTuple_GET_SIZE(call_shape.kwnames) == kwnames_len)
|
||||
);
|
||||
int nargs = call_shape.total_args - kwnames_len;
|
||||
STACK_SHRINK(call_shape.total_args);
|
||||
STACK_SHRINK(total_args);
|
||||
/* res = func(self, args, nargs, kwnames) */
|
||||
_PyCFunctionFastWithKeywords cfunc =
|
||||
(_PyCFunctionFastWithKeywords)(void(*)(void))
|
||||
|
@ -4873,17 +4886,17 @@ handle_eval_breaker:
|
|||
PyObject *res = cfunc(
|
||||
PyCFunction_GET_SELF(callable),
|
||||
stack_pointer,
|
||||
nargs,
|
||||
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 < call_shape.total_args; i++) {
|
||||
for (int i = 0; i < total_args; i++) {
|
||||
Py_DECREF(stack_pointer[i]);
|
||||
}
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
PUSH(res);
|
||||
Py_DECREF(callable);
|
||||
if (res == NULL) {
|
||||
|
@ -4898,11 +4911,12 @@ handle_eval_breaker:
|
|||
assert(call_shape.kwnames == NULL);
|
||||
/* len(o) */
|
||||
SpecializedCacheEntry *caches = GET_CACHE();
|
||||
DEOPT_IF(call_shape.total_args != 1, CALL);
|
||||
assert(caches[0].adaptive.original_oparg == 0);
|
||||
int original_oparg = caches->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
DEOPT_IF(total_args != 1, CALL);
|
||||
_PyObjectCache *cache1 = &caches[-1].obj;
|
||||
|
||||
PyObject *callable = call_shape.callable;
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
DEOPT_IF(callable != cache1->obj, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
|
||||
|
@ -4914,7 +4928,7 @@ handle_eval_breaker:
|
|||
PyObject *res = PyLong_FromSsize_t(len_i);
|
||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
SET_TOP(res);
|
||||
Py_DECREF(callable);
|
||||
Py_DECREF(arg);
|
||||
|
@ -4929,11 +4943,14 @@ handle_eval_breaker:
|
|||
assert(call_shape.kwnames == NULL);
|
||||
/* isinstance(o, o2) */
|
||||
SpecializedCacheEntry *caches = GET_CACHE();
|
||||
assert(caches[0].adaptive.original_oparg == 0);
|
||||
DEOPT_IF(call_shape.total_args != 2, CALL);
|
||||
int original_oparg = caches->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
DEOPT_IF(total_args != 2, CALL);
|
||||
_PyObjectCache *cache1 = &caches[-1].obj;
|
||||
|
||||
DEOPT_IF(call_shape.callable != cache1->obj, CALL);
|
||||
DEOPT_IF(callable != cache1->obj, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
|
||||
PyObject *cls = POP();
|
||||
|
@ -4946,11 +4963,11 @@ handle_eval_breaker:
|
|||
PyObject *res = PyBool_FromLong(retval);
|
||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
SET_TOP(res);
|
||||
Py_DECREF(inst);
|
||||
Py_DECREF(cls);
|
||||
Py_DECREF(call_shape.callable);
|
||||
Py_DECREF(callable);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -4961,9 +4978,13 @@ handle_eval_breaker:
|
|||
assert(cframe.use_tracing == 0);
|
||||
assert(call_shape.kwnames == NULL);
|
||||
SpecializedCacheEntry *caches = GET_CACHE();
|
||||
int original_oparg = caches->adaptive.original_oparg;
|
||||
_PyObjectCache *cache1 = &caches[-1].obj;
|
||||
DEOPT_IF(call_shape.total_args != 2, CALL);
|
||||
DEOPT_IF(call_shape.callable != cache1->obj, CALL);
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
DEOPT_IF(total_args != 2, CALL);
|
||||
DEOPT_IF(callable != cache1->obj, CALL);
|
||||
PyObject *list = SECOND();
|
||||
DEOPT_IF(!PyList_Check(list), CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
|
@ -4974,18 +4995,22 @@ handle_eval_breaker:
|
|||
}
|
||||
Py_DECREF(arg);
|
||||
Py_DECREF(list);
|
||||
STACK_SHRINK(call_shape.postcall_shrink+1);
|
||||
STACK_SHRINK(3-is_meth);
|
||||
Py_INCREF(Py_None);
|
||||
SET_TOP(Py_None);
|
||||
Py_DECREF(call_shape.callable);
|
||||
Py_DECREF(callable);
|
||||
NOTRACE_DISPATCH();
|
||||
}
|
||||
|
||||
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) {
|
||||
assert(call_shape.kwnames == NULL);
|
||||
DEOPT_IF(call_shape.total_args != 2, CALL);
|
||||
DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL);
|
||||
PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method;
|
||||
int original_oparg = GET_CACHE()->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
DEOPT_IF(total_args != 2, CALL);
|
||||
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
|
||||
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
|
||||
DEOPT_IF(meth->ml_flags != METH_O, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
PyCFunction cfunc = meth->ml_meth;
|
||||
|
@ -5001,9 +5026,9 @@ handle_eval_breaker:
|
|||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
Py_DECREF(self);
|
||||
Py_DECREF(arg);
|
||||
STACK_SHRINK(call_shape.postcall_shrink+1);
|
||||
STACK_SHRINK(3-is_meth);
|
||||
SET_TOP(res);
|
||||
Py_DECREF(call_shape.callable);
|
||||
Py_DECREF(callable);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -5013,9 +5038,13 @@ handle_eval_breaker:
|
|||
|
||||
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) {
|
||||
assert(call_shape.kwnames == NULL);
|
||||
DEOPT_IF(call_shape.total_args != 1, CALL);
|
||||
DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL);
|
||||
PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method;
|
||||
int original_oparg = GET_CACHE()->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
DEOPT_IF(total_args != 1, CALL);
|
||||
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
|
||||
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
|
||||
DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
PyCFunction cfunc = meth->ml_meth;
|
||||
|
@ -5029,9 +5058,9 @@ handle_eval_breaker:
|
|||
_Py_LeaveRecursiveCall(tstate);
|
||||
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
|
||||
Py_DECREF(self);
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
SET_TOP(res);
|
||||
Py_DECREF(call_shape.callable);
|
||||
Py_DECREF(callable);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
@ -5041,13 +5070,17 @@ handle_eval_breaker:
|
|||
|
||||
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) {
|
||||
assert(call_shape.kwnames == NULL);
|
||||
int original_oparg = GET_CACHE()->adaptive.original_oparg;
|
||||
int is_meth = is_method(stack_pointer, original_oparg);
|
||||
int total_args = original_oparg + is_meth;
|
||||
PyObject *callable = PEEK(total_args + 1);
|
||||
/* Builtin METH_FASTCALL methods, without keywords */
|
||||
DEOPT_IF(!Py_IS_TYPE(call_shape.callable, &PyMethodDescr_Type), CALL);
|
||||
PyMethodDef *meth = ((PyMethodDescrObject *)call_shape.callable)->d_method;
|
||||
DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
|
||||
PyMethodDef *meth = ((PyMethodDescrObject *)callable)->d_method;
|
||||
DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL);
|
||||
STAT_INC(CALL, hit);
|
||||
_PyCFunctionFast cfunc = (_PyCFunctionFast)(void(*)(void))meth->ml_meth;
|
||||
int nargs = call_shape.total_args-1;
|
||||
int nargs = total_args-1;
|
||||
STACK_SHRINK(nargs);
|
||||
PyObject *self = TOP();
|
||||
PyObject *res = cfunc(self, stack_pointer, nargs);
|
||||
|
@ -5057,9 +5090,9 @@ handle_eval_breaker:
|
|||
Py_DECREF(stack_pointer[i]);
|
||||
}
|
||||
Py_DECREF(self);
|
||||
STACK_SHRINK(call_shape.postcall_shrink);
|
||||
STACK_SHRINK(2-is_meth);
|
||||
SET_TOP(res);
|
||||
Py_DECREF(call_shape.callable);
|
||||
Py_DECREF(callable);
|
||||
if (res == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
|
|
@ -1800,7 +1800,7 @@ compiler_call_exit_with_nones(struct compiler *c) {
|
|||
ADDOP_LOAD_CONST(c, Py_None);
|
||||
ADDOP_LOAD_CONST(c, Py_None);
|
||||
ADDOP_I(c, PRECALL, 2);
|
||||
ADDOP_I(c, CALL, 0);
|
||||
ADDOP_I(c, CALL, 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -4679,16 +4679,12 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
|
|||
|
||||
if (kwdsl) {
|
||||
VISIT_SEQ(c, keyword, kwds);
|
||||
ADDOP_I(c, PRECALL, argsl + kwdsl);
|
||||
if (!compiler_call_simple_kw_helper(c, kwds, kwdsl)) {
|
||||
return 0;
|
||||
};
|
||||
ADDOP_I(c, CALL, kwdsl);
|
||||
}
|
||||
else {
|
||||
ADDOP_I(c, PRECALL, argsl);
|
||||
ADDOP_I(c, CALL, 0);
|
||||
}
|
||||
ADDOP_I(c, PRECALL, argsl + kwdsl);
|
||||
ADDOP_I(c, CALL, argsl + kwdsl);
|
||||
c->u->u_lineno = old_lineno;
|
||||
return 1;
|
||||
}
|
||||
|
@ -4758,7 +4754,7 @@ compiler_joined_str(struct compiler *c, expr_ty e)
|
|||
ADDOP_I(c, LIST_APPEND, 1);
|
||||
}
|
||||
ADDOP_I(c, PRECALL, 1);
|
||||
ADDOP_I(c, CALL, 0);
|
||||
ADDOP_I(c, CALL, 1);
|
||||
}
|
||||
else {
|
||||
VISIT_SEQ(c, expr, e->v.JoinedStr.values);
|
||||
|
@ -4927,18 +4923,13 @@ compiler_call_helper(struct compiler *c,
|
|||
}
|
||||
if (nkwelts) {
|
||||
VISIT_SEQ(c, keyword, keywords);
|
||||
ADDOP_I(c, PRECALL, n + nelts + nkwelts);
|
||||
if (!compiler_call_simple_kw_helper(c, keywords, nkwelts)) {
|
||||
return 0;
|
||||
};
|
||||
ADDOP_I(c, CALL, nkwelts);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
ADDOP_I(c, PRECALL, n + nelts);
|
||||
ADDOP_I(c, CALL, 0);
|
||||
return 1;
|
||||
}
|
||||
ADDOP_I(c, PRECALL, n + nelts + nkwelts);
|
||||
ADDOP_I(c, CALL, n + nelts + nkwelts);
|
||||
return 1;
|
||||
|
||||
ex_call:
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue