summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2022-02-21 18:26:47 (GMT)
committerGitHub <noreply@github.com>2022-02-21 18:26:47 (GMT)
commit59585d6b2ea50d7bc3a9b336da5bde61367f527c (patch)
tree582cbdf9fd0c4e3b3e19e3474154b1a252a97654 /Python
parent0a222db2bca63070f429c0e613707da1bdfaf0e0 (diff)
downloadcpython-59585d6b2ea50d7bc3a9b336da5bde61367f527c.zip
cpython-59585d6b2ea50d7bc3a9b336da5bde61367f527c.tar.gz
cpython-59585d6b2ea50d7bc3a9b336da5bde61367f527c.tar.bz2
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
Diffstat (limited to 'Python')
-rw-r--r--Python/ceval.c269
-rw-r--r--Python/compile.c23
2 files changed, 158 insertions, 134 deletions
diff --git a/Python/ceval.c b/Python/ceval.c
index 471bbde..d3ab1da 100644
--- a/Python/ceval.c
+++ b/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;
}
diff --git a/Python/compile.c b/Python/compile.c
index 645213b..7f0a6f0 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -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: