diff options
author | Mark Shannon <mark@hotpy.org> | 2022-02-21 18:26:47 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-21 18:26:47 (GMT) |
commit | 59585d6b2ea50d7bc3a9b336da5bde61367f527c (patch) | |
tree | 582cbdf9fd0c4e3b3e19e3474154b1a252a97654 /Python | |
parent | 0a222db2bca63070f429c0e613707da1bdfaf0e0 (diff) | |
download | cpython-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.c | 269 | ||||
-rw-r--r-- | Python/compile.c | 23 |
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: |