diff options
Diffstat (limited to 'Python')
-rw-r--r-- | Python/abstract_interp_cases.c.h | 41 | ||||
-rw-r--r-- | Python/bytecodes.c | 190 | ||||
-rw-r--r-- | Python/ceval.c | 2 | ||||
-rw-r--r-- | Python/ceval_macros.h | 5 | ||||
-rw-r--r-- | Python/compile.c | 22 | ||||
-rw-r--r-- | Python/executor_cases.c.h | 140 | ||||
-rw-r--r-- | Python/flowgraph.c | 2 | ||||
-rw-r--r-- | Python/generated_cases.c.h | 173 | ||||
-rw-r--r-- | Python/instrumentation.c | 5 | ||||
-rw-r--r-- | Python/opcode_targets.h | 28 | ||||
-rw-r--r-- | Python/specialize.c | 82 |
11 files changed, 444 insertions, 246 deletions
diff --git a/Python/abstract_interp_cases.c.h b/Python/abstract_interp_cases.c.h index 1b96ca1..5a3848c 100644 --- a/Python/abstract_interp_cases.c.h +++ b/Python/abstract_interp_cases.c.h @@ -661,21 +661,21 @@ break; } - case CALL_NO_KW_TYPE_1: { + case CALL_TYPE_1: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); break; } - case CALL_NO_KW_STR_1: { + case CALL_STR_1: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); break; } - case CALL_NO_KW_TUPLE_1: { + case CALL_TUPLE_1: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); @@ -687,49 +687,70 @@ break; } - case CALL_NO_KW_BUILTIN_O: { + case CALL_BUILTIN_CLASS: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); break; } - case CALL_NO_KW_BUILTIN_FAST: { + case CALL_BUILTIN_O: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); break; } - case CALL_NO_KW_LEN: { + case CALL_BUILTIN_FAST: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); break; } - case CALL_NO_KW_ISINSTANCE: { + case CALL_BUILTIN_FAST_WITH_KEYWORDS: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); break; } - case CALL_NO_KW_METHOD_DESCRIPTOR_O: { + case CALL_LEN: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); break; } - case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: { + case CALL_ISINSTANCE: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); break; } - case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: { + case CALL_METHOD_DESCRIPTOR_O: { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); + break; + } + + case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); + break; + } + + case CALL_METHOD_DESCRIPTOR_NOARGS: { + STACK_SHRINK(oparg); + STACK_SHRINK(1); + PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); + break; + } + + case CALL_METHOD_DESCRIPTOR_FAST: { STACK_SHRINK(oparg); STACK_SHRINK(1); PARTITIONNODE_OVERWRITE((_Py_PARTITIONNODE_t *)PARTITIONNODE_NULLROOT, PEEK(-(-1)), true); diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 08d91b5..e5be62c 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -74,7 +74,6 @@ dummy_func( unsigned int oparg, _Py_CODEUNIT *next_instr, PyObject **stack_pointer, - PyObject *kwnames, int throwflag, PyObject *args[] ) @@ -2854,12 +2853,6 @@ dummy_func( self = owner; } - inst(KW_NAMES, (--)) { - ASSERT_KWNAMES_IS_NULL(); - assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); - kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - } - inst(INSTRUMENTED_CALL, ( -- )) { int is_meth = PEEK(oparg + 1) != NULL; int total_args = oparg + is_meth; @@ -2876,36 +2869,31 @@ dummy_func( } // Cache layout: counter/1, func_version/2 - // Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members! + // CALL_INTRINSIC_1/2, CALL_KW, and CALL_FUNCTION_EX aren't members! family(CALL, INLINE_CACHE_ENTRIES_CALL) = { CALL_BOUND_METHOD_EXACT_ARGS, CALL_PY_EXACT_ARGS, CALL_PY_WITH_DEFAULTS, - CALL_NO_KW_TYPE_1, - CALL_NO_KW_STR_1, - CALL_NO_KW_TUPLE_1, + CALL_TYPE_1, + CALL_STR_1, + CALL_TUPLE_1, CALL_BUILTIN_CLASS, - CALL_NO_KW_BUILTIN_O, - CALL_NO_KW_BUILTIN_FAST, + CALL_BUILTIN_O, + CALL_BUILTIN_FAST, CALL_BUILTIN_FAST_WITH_KEYWORDS, - CALL_NO_KW_LEN, - CALL_NO_KW_ISINSTANCE, - CALL_NO_KW_LIST_APPEND, - CALL_NO_KW_METHOD_DESCRIPTOR_O, + CALL_LEN, + CALL_ISINSTANCE, + CALL_LIST_APPEND, + CALL_METHOD_DESCRIPTOR_O, CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, - CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, - CALL_NO_KW_METHOD_DESCRIPTOR_FAST, - CALL_NO_KW_ALLOC_AND_ENTER_INIT, + CALL_METHOD_DESCRIPTOR_NOARGS, + CALL_METHOD_DESCRIPTOR_FAST, + CALL_ALLOC_AND_ENTER_INIT, }; - // On entry, the stack is either - // [NULL, callable, arg1, arg2, ...] - // or - // [method, self, arg1, arg2, ...] - // (Some args may be keywords, see KW_NAMES, which sets 'kwnames'.) - // On exit, the stack is [result]. // When calling Python, inline the call using DISPATCH_INLINED(). inst(CALL, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { + // oparg counts all of the args, but *not* self: int total_args = oparg; if (self_or_null != NULL) { args--; @@ -2915,7 +2903,7 @@ dummy_func( _PyCallCache *cache = (_PyCallCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; - _Py_Specialize_Call(callable, next_instr, total_args, kwnames); + _Py_Specialize_Call(callable, next_instr, total_args); DISPATCH_SAME_OPARG(); } STAT_INC(CALL, deferred); @@ -2931,7 +2919,6 @@ dummy_func( Py_DECREF(callable); callable = method; } - int positional_args = total_args - KWNAMES_LEN(); // Check if the call can be inlined or not if (Py_TYPE(callable) == &PyFunction_Type && tstate->interp->eval_frame == NULL && @@ -2941,9 +2928,8 @@ dummy_func( PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( tstate, (PyFunctionObject *)callable, locals, - args, positional_args, kwnames + args, total_args, NULL ); - kwnames = NULL; // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); // The frame has stolen all the arguments from the stack, @@ -2958,8 +2944,8 @@ dummy_func( /* Callable is not a normal Python function */ res = PyObject_Vectorcall( callable, args, - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames); + total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + NULL); if (opcode == INSTRUMENTED_CALL) { PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : args[0]; @@ -2977,7 +2963,6 @@ dummy_func( } } } - kwnames = NULL; assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(callable); for (int i = 0; i < total_args; i++) { @@ -3006,7 +2991,6 @@ dummy_func( } op(_CHECK_FUNCTION_EXACT_ARGS, (func_version/2, callable, self_or_null, unused[oparg] -- callable, self_or_null, unused[oparg])) { - ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(!PyFunction_Check(callable), CALL); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); @@ -3081,7 +3065,6 @@ dummy_func( _PUSH_FRAME; inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) { - ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); int argcount = oparg; if (self_or_null != NULL) { @@ -3116,8 +3099,7 @@ dummy_func( DISPATCH_INLINED(new_frame); } - inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) { - ASSERT_KWNAMES_IS_NULL(); + inst(CALL_TYPE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) { assert(oparg == 1); DEOPT_IF(null != NULL, CALL); PyObject *obj = args[0]; @@ -3128,8 +3110,7 @@ dummy_func( Py_DECREF(&PyType_Type); // I.e., callable } - inst(CALL_NO_KW_STR_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) { - ASSERT_KWNAMES_IS_NULL(); + inst(CALL_STR_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) { assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); @@ -3142,8 +3123,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) { - ASSERT_KWNAMES_IS_NULL(); + inst(CALL_TUPLE_1, (unused/1, unused/2, callable, null, args[oparg] -- res)) { assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); @@ -3156,13 +3136,12 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, callable, null, args[oparg] -- unused)) { + inst(CALL_ALLOC_AND_ENTER_INIT, (unused/1, unused/2, callable, null, args[oparg] -- unused)) { /* This instruction does the following: * 1. Creates the object (by calling ``object.__new__``) * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) * 3. Pushes the frame for ``__init__`` to the frame stack * */ - ASSERT_KWNAMES_IS_NULL(); _PyCallCache *cache = (_PyCallCache *)next_instr; DEOPT_IF(null != NULL, CALL); DEOPT_IF(!PyType_Check(callable), CALL); @@ -3225,14 +3204,11 @@ dummy_func( args--; total_args++; } - int kwnames_len = KWNAMES_LEN(); DEOPT_IF(!PyType_Check(callable), CALL); PyTypeObject *tp = (PyTypeObject *)callable; DEOPT_IF(tp->tp_vectorcall == NULL, CALL); STAT_INC(CALL, hit); - res = tp->tp_vectorcall((PyObject *)tp, args, - total_args - kwnames_len, kwnames); - kwnames = NULL; + res = tp->tp_vectorcall((PyObject *)tp, args, total_args, NULL); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); @@ -3242,9 +3218,8 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { + inst(CALL_BUILTIN_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { /* Builtin METH_O functions */ - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -3271,9 +3246,8 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { + inst(CALL_BUILTIN_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { /* Builtin METH_FASTCALL functions, without keywords */ - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -3319,14 +3293,8 @@ dummy_func( _PyCFunctionFastWithKeywords cfunc = (_PyCFunctionFastWithKeywords)(void(*)(void)) PyCFunction_GET_FUNCTION(callable); - res = cfunc( - PyCFunction_GET_SELF(callable), - args, - total_args - KWNAMES_LEN(), - kwnames - ); + res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { @@ -3337,8 +3305,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_LEN, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { - ASSERT_KWNAMES_IS_NULL(); + inst(CALL_LEN, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { /* len(o) */ int total_args = oparg; if (self_or_null != NULL) { @@ -3362,8 +3329,7 @@ dummy_func( ERROR_IF(res == NULL, error); } - inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { - ASSERT_KWNAMES_IS_NULL(); + inst(CALL_ISINSTANCE, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { /* isinstance(o, o2) */ int total_args = oparg; if (self_or_null != NULL) { @@ -3390,8 +3356,7 @@ dummy_func( } // This is secretly a super-instruction - inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, callable, self, args[oparg] -- unused)) { - ASSERT_KWNAMES_IS_NULL(); + inst(CALL_LIST_APPEND, (unused/1, unused/2, callable, self, args[oparg] -- unused)) { assert(oparg == 1); PyInterpreterState *interp = tstate->interp; DEOPT_IF(callable != interp->callable_cache.list_append, CALL); @@ -3410,8 +3375,7 @@ dummy_func( DISPATCH(); } - inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { - ASSERT_KWNAMES_IS_NULL(); + inst(CALL_METHOD_DESCRIPTOR_O, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { int total_args = oparg; if (self_or_null != NULL) { args--; @@ -3459,9 +3423,8 @@ dummy_func( int nargs = total_args - 1; _PyCFunctionFastWithKeywords cfunc = (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; - res = cfunc(self, args + 1, nargs - KWNAMES_LEN(), kwnames); + res = cfunc(self, args + 1, nargs, NULL); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { @@ -3472,8 +3435,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { - ASSERT_KWNAMES_IS_NULL(); + inst(CALL_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { assert(oparg == 0 || oparg == 1); int total_args = oparg; if (self_or_null != NULL) { @@ -3503,8 +3465,7 @@ dummy_func( CHECK_EVAL_BREAKER(); } - inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { - ASSERT_KWNAMES_IS_NULL(); + inst(CALL_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, callable, self_or_null, args[oparg] -- res)) { int total_args = oparg; if (self_or_null != NULL) { args--; @@ -3532,6 +3493,91 @@ dummy_func( CHECK_EVAL_BREAKER(); } + inst(INSTRUMENTED_CALL_KW, ( -- )) { + int is_meth = PEEK(oparg + 2) != NULL; + int total_args = oparg + is_meth; + PyObject *function = PEEK(oparg + 3); + PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING + : PEEK(total_args + 1); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, next_instr - 1, function, arg); + ERROR_IF(err, error); + GO_TO_INSTRUCTION(CALL_KW); + } + + inst(CALL_KW, (callable, self_or_null, args[oparg], kwnames -- res)) { + // oparg counts all of the args, but *not* self: + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + if (self_or_null == NULL && Py_TYPE(callable) == &PyMethod_Type) { + args--; + total_args++; + PyObject *self = ((PyMethodObject *)callable)->im_self; + args[0] = Py_NewRef(self); + PyObject *method = ((PyMethodObject *)callable)->im_func; + args[-1] = Py_NewRef(method); + Py_DECREF(callable); + callable = method; + } + int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames); + // Check if the call can be inlined or not + if (Py_TYPE(callable) == &PyFunction_Type && + tstate->interp->eval_frame == NULL && + ((PyFunctionObject *)callable)->vectorcall == _PyFunction_Vectorcall) + { + int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, (PyFunctionObject *)callable, locals, + args, positional_args, kwnames + ); + Py_DECREF(kwnames); + // Manipulate stack directly since we leave using DISPATCH_INLINED(). + STACK_SHRINK(oparg + 3); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + if (new_frame == NULL) { + goto error; + } + frame->return_offset = 0; + DISPATCH_INLINED(new_frame); + } + /* Callable is not a normal Python function */ + res = PyObject_Vectorcall( + callable, args, + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames); + if (opcode == INSTRUMENTED_CALL_KW) { + PyObject *arg = total_args == 0 ? + &_PyInstrumentation_MISSING : args[0]; + if (res == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, next_instr-1, callable, arg); + } + else { + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, next_instr-1, callable, arg); + if (err < 0) { + Py_CLEAR(res); + } + } + } + Py_DECREF(kwnames); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(callable); + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + ERROR_IF(res == NULL, error); + CHECK_EVAL_BREAKER(); + } + inst(INSTRUMENTED_CALL_FUNCTION_EX, ( -- )) { GO_TO_INSTRUCTION(CALL_FUNCTION_EX); } diff --git a/Python/ceval.c b/Python/ceval.c index b02bf60..cae29e0 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -678,7 +678,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int #endif _PyInterpreterFrame entry_frame; - PyObject *kwnames = NULL; // Borrowed reference. Reset by CALL instructions. @@ -840,7 +839,6 @@ pop_2_error: pop_1_error: STACK_SHRINK(1); error: - kwnames = NULL; /* Double-check exception status. */ #ifdef NDEBUG if (!_PyErr_Occurred(tstate)) { diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h index f5d9155..012750d 100644 --- a/Python/ceval_macros.h +++ b/Python/ceval_macros.h @@ -311,9 +311,6 @@ GETITEM(PyObject *v, Py_ssize_t i) { " in enclosing scope" #define NAME_ERROR_MSG "name '%.200s' is not defined" -#define KWNAMES_LEN() \ - (kwnames == NULL ? 0 : ((int)PyTuple_GET_SIZE(kwnames))) - #define DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dval, result) \ do { \ if (Py_REFCNT(left) == 1) { \ @@ -356,8 +353,6 @@ static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = { [FVC_ASCII] = PyObject_ASCII }; -#define ASSERT_KWNAMES_IS_NULL() assert(kwnames == NULL) - // GH-89279: Force inlining by using a macro. #if defined(_MSC_VER) && SIZEOF_INT == 4 #define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) (assert(sizeof((ATOMIC_VAL)->_value) == 4), *((volatile int*)&((ATOMIC_VAL)->_value))) diff --git a/Python/compile.c b/Python/compile.c index 1f08e46..b05c1ad 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -4982,9 +4982,13 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e) VISIT_SEQ(c, keyword, kwds); RETURN_IF_ERROR( compiler_call_simple_kw_helper(c, loc, kwds, kwdsl)); + loc = update_start_location_to_match_attr(c, LOC(e), meth); + ADDOP_I(c, loc, CALL_KW, argsl + kwdsl); + } + else { + loc = update_start_location_to_match_attr(c, LOC(e), meth); + ADDOP_I(c, loc, CALL, argsl); } - loc = update_start_location_to_match_attr(c, LOC(e), meth); - ADDOP_I(c, loc, CALL, argsl + kwdsl); return 1; } @@ -5150,7 +5154,7 @@ compiler_subkwargs(struct compiler *c, location loc, } /* Used by compiler_call_helper and maybe_optimize_method_call to emit - * KW_NAMES before CALL. + * a tuple of keyword names before CALL. */ static int compiler_call_simple_kw_helper(struct compiler *c, location loc, @@ -5165,12 +5169,7 @@ compiler_call_simple_kw_helper(struct compiler *c, location loc, keyword_ty kw = asdl_seq_GET(keywords, i); PyTuple_SET_ITEM(names, i, Py_NewRef(kw->arg)); } - Py_ssize_t arg = compiler_add_const(c->c_const_cache, c->u, names); - if (arg < 0) { - return ERROR; - } - Py_DECREF(names); - ADDOP_I(c, loc, KW_NAMES, arg); + ADDOP_LOAD_CONST_NEW(c, loc, names); return SUCCESS; } @@ -5215,8 +5214,11 @@ compiler_call_helper(struct compiler *c, location loc, VISIT_SEQ(c, keyword, keywords); RETURN_IF_ERROR( compiler_call_simple_kw_helper(c, loc, keywords, nkwelts)); + ADDOP_I(c, loc, CALL_KW, n + nelts + nkwelts); + } + else { + ADDOP_I(c, loc, CALL, n + nelts); } - ADDOP_I(c, loc, CALL, n + nelts + nkwelts); return SUCCESS; ex_call: diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 8f3febe..befb972 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -2256,7 +2256,6 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; uint32_t func_version = (uint32_t)operand; - ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(!PyFunction_Check(callable), CALL); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); @@ -2324,7 +2323,7 @@ break; } - case CALL_NO_KW_TYPE_1: { + case CALL_TYPE_1: { PyObject **args; PyObject *null; PyObject *callable; @@ -2332,7 +2331,6 @@ args = stack_pointer - oparg; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); PyObject *obj = args[0]; @@ -2347,7 +2345,7 @@ break; } - case CALL_NO_KW_STR_1: { + case CALL_STR_1: { PyObject **args; PyObject *null; PyObject *callable; @@ -2355,7 +2353,6 @@ args = stack_pointer - oparg; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); @@ -2372,7 +2369,7 @@ break; } - case CALL_NO_KW_TUPLE_1: { + case CALL_TUPLE_1: { PyObject **args; PyObject *null; PyObject *callable; @@ -2380,7 +2377,6 @@ args = stack_pointer - oparg; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); @@ -2411,7 +2407,38 @@ break; } - case CALL_NO_KW_BUILTIN_O: { + case CALL_BUILTIN_CLASS: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + PyObject *res; + args = stack_pointer - oparg; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + DEOPT_IF(!PyType_Check(callable), CALL); + PyTypeObject *tp = (PyTypeObject *)callable; + DEOPT_IF(tp->tp_vectorcall == NULL, CALL); + STAT_INC(CALL, hit); + res = tp->tp_vectorcall((PyObject *)tp, args, total_args, NULL); + /* Free the arguments. */ + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + Py_DECREF(tp); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + CHECK_EVAL_BREAKER(); + break; + } + + case CALL_BUILTIN_O: { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -2420,7 +2447,6 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* Builtin METH_O functions */ - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -2451,7 +2477,7 @@ break; } - case CALL_NO_KW_BUILTIN_FAST: { + case CALL_BUILTIN_FAST: { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -2460,7 +2486,6 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL functions, without keywords */ - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -2495,7 +2520,45 @@ break; } - case CALL_NO_KW_LEN: { + case CALL_BUILTIN_FAST_WITH_KEYWORDS: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + PyObject *res; + args = stack_pointer - oparg; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + /* Builtin METH_FASTCALL | METH_KEYWORDS functions */ + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + DEOPT_IF(!PyCFunction_CheckExact(callable), CALL); + DEOPT_IF(PyCFunction_GET_FLAGS(callable) != + (METH_FASTCALL | METH_KEYWORDS), CALL); + STAT_INC(CALL, hit); + /* res = func(self, args, nargs, kwnames) */ + _PyCFunctionFastWithKeywords cfunc = + (_PyCFunctionFastWithKeywords)(void(*)(void)) + PyCFunction_GET_FUNCTION(callable); + res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + /* Free the arguments. */ + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + Py_DECREF(callable); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + CHECK_EVAL_BREAKER(); + break; + } + + case CALL_LEN: { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -2503,7 +2566,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); /* len(o) */ int total_args = oparg; if (self_or_null != NULL) { @@ -2531,7 +2593,7 @@ break; } - case CALL_NO_KW_ISINSTANCE: { + case CALL_ISINSTANCE: { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -2539,7 +2601,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); /* isinstance(o, o2) */ int total_args = oparg; if (self_or_null != NULL) { @@ -2569,7 +2630,7 @@ break; } - case CALL_NO_KW_METHOD_DESCRIPTOR_O: { + case CALL_METHOD_DESCRIPTOR_O: { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -2577,7 +2638,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -2612,7 +2672,47 @@ break; } - case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: { + case CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS: { + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + PyObject *res; + args = stack_pointer - oparg; + self_or_null = stack_pointer[-1 - oparg]; + callable = stack_pointer[-2 - oparg]; + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + PyMethodDescrObject *method = (PyMethodDescrObject *)callable; + DEOPT_IF(!Py_IS_TYPE(method, &PyMethodDescr_Type), CALL); + PyMethodDef *meth = method->d_method; + DEOPT_IF(meth->ml_flags != (METH_FASTCALL|METH_KEYWORDS), CALL); + PyTypeObject *d_type = method->d_common.d_type; + PyObject *self = args[0]; + DEOPT_IF(!Py_IS_TYPE(self, d_type), CALL); + STAT_INC(CALL, hit); + int nargs = total_args - 1; + _PyCFunctionFastWithKeywords cfunc = + (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; + res = cfunc(self, args + 1, nargs, NULL); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + + /* Free the arguments. */ + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + Py_DECREF(callable); + if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(1); + stack_pointer[-1] = res; + CHECK_EVAL_BREAKER(); + break; + } + + case CALL_METHOD_DESCRIPTOR_NOARGS: { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -2620,7 +2720,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); assert(oparg == 0 || oparg == 1); int total_args = oparg; if (self_or_null != NULL) { @@ -2654,7 +2753,7 @@ break; } - case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: { + case CALL_METHOD_DESCRIPTOR_FAST: { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -2662,7 +2761,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; diff --git a/Python/flowgraph.c b/Python/flowgraph.c index 55b871d..44858b9 100644 --- a/Python/flowgraph.c +++ b/Python/flowgraph.c @@ -1624,8 +1624,6 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) INSTR_SET_OP0(inst, NOP); } break; - case KW_NAMES: - break; case LOAD_GLOBAL: if (nextop == PUSH_NULL && (oparg & 1) == 0) { INSTR_SET_OP1(inst, LOAD_GLOBAL, oparg | 1); diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index 9742c95..fff47a1 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -3688,13 +3688,6 @@ DISPATCH(); } - TARGET(KW_NAMES) { - ASSERT_KWNAMES_IS_NULL(); - assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS)); - kwnames = GETITEM(FRAME_CO_CONSTS, oparg); - DISPATCH(); - } - TARGET(INSTRUMENTED_CALL) { int is_meth = PEEK(oparg + 1) != NULL; int total_args = oparg + is_meth; @@ -3720,6 +3713,7 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; + // oparg counts all of the args, but *not* self: int total_args = oparg; if (self_or_null != NULL) { args--; @@ -3729,7 +3723,7 @@ _PyCallCache *cache = (_PyCallCache *)next_instr; if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) { next_instr--; - _Py_Specialize_Call(callable, next_instr, total_args, kwnames); + _Py_Specialize_Call(callable, next_instr, total_args); DISPATCH_SAME_OPARG(); } STAT_INC(CALL, deferred); @@ -3745,7 +3739,6 @@ Py_DECREF(callable); callable = method; } - int positional_args = total_args - KWNAMES_LEN(); // Check if the call can be inlined or not if (Py_TYPE(callable) == &PyFunction_Type && tstate->interp->eval_frame == NULL && @@ -3755,9 +3748,8 @@ PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( tstate, (PyFunctionObject *)callable, locals, - args, positional_args, kwnames + args, total_args, NULL ); - kwnames = NULL; // Manipulate stack directly since we leave using DISPATCH_INLINED(). STACK_SHRINK(oparg + 2); // The frame has stolen all the arguments from the stack, @@ -3772,8 +3764,8 @@ /* Callable is not a normal Python function */ res = PyObject_Vectorcall( callable, args, - positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, - kwnames); + total_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + NULL); if (opcode == INSTRUMENTED_CALL) { PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING : args[0]; @@ -3791,7 +3783,6 @@ } } } - kwnames = NULL; assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); Py_DECREF(callable); for (int i = 0; i < total_args; i++) { @@ -3839,7 +3830,6 @@ callable = func; { uint32_t func_version = read_u32(&next_instr[1].cache); - ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(!PyFunction_Check(callable), CALL); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); @@ -3918,7 +3908,6 @@ callable = stack_pointer[-2 - oparg]; { uint32_t func_version = read_u32(&next_instr[1].cache); - ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(!PyFunction_Check(callable), CALL); PyFunctionObject *func = (PyFunctionObject *)callable; DEOPT_IF(func->func_version != func_version, CALL); @@ -3991,7 +3980,6 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; uint32_t func_version = read_u32(&next_instr[1].cache); - ASSERT_KWNAMES_IS_NULL(); DEOPT_IF(tstate->interp->eval_frame, CALL); int argcount = oparg; if (self_or_null != NULL) { @@ -4026,7 +4014,7 @@ DISPATCH_INLINED(new_frame); } - TARGET(CALL_NO_KW_TYPE_1) { + TARGET(CALL_TYPE_1) { PyObject **args; PyObject *null; PyObject *callable; @@ -4034,7 +4022,6 @@ args = stack_pointer - oparg; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); PyObject *obj = args[0]; @@ -4050,7 +4037,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_STR_1) { + TARGET(CALL_STR_1) { PyObject **args; PyObject *null; PyObject *callable; @@ -4058,7 +4045,6 @@ args = stack_pointer - oparg; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL); @@ -4076,7 +4062,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_TUPLE_1) { + TARGET(CALL_TUPLE_1) { PyObject **args; PyObject *null; PyObject *callable; @@ -4084,7 +4070,6 @@ args = stack_pointer - oparg; null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); DEOPT_IF(null != NULL, CALL); DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL); @@ -4102,7 +4087,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_ALLOC_AND_ENTER_INIT) { + TARGET(CALL_ALLOC_AND_ENTER_INIT) { PyObject **args; PyObject *null; PyObject *callable; @@ -4114,7 +4099,6 @@ * 2. Pushes a shim frame to the frame stack (to cleanup after ``__init__``) * 3. Pushes the frame for ``__init__`` to the frame stack * */ - ASSERT_KWNAMES_IS_NULL(); _PyCallCache *cache = (_PyCallCache *)next_instr; DEOPT_IF(null != NULL, CALL); DEOPT_IF(!PyType_Check(callable), CALL); @@ -4188,14 +4172,11 @@ args--; total_args++; } - int kwnames_len = KWNAMES_LEN(); DEOPT_IF(!PyType_Check(callable), CALL); PyTypeObject *tp = (PyTypeObject *)callable; DEOPT_IF(tp->tp_vectorcall == NULL, CALL); STAT_INC(CALL, hit); - res = tp->tp_vectorcall((PyObject *)tp, args, - total_args - kwnames_len, kwnames); - kwnames = NULL; + res = tp->tp_vectorcall((PyObject *)tp, args, total_args, NULL); /* Free the arguments. */ for (int i = 0; i < total_args; i++) { Py_DECREF(args[i]); @@ -4210,7 +4191,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_BUILTIN_O) { + TARGET(CALL_BUILTIN_O) { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -4219,7 +4200,6 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* Builtin METH_O functions */ - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -4251,7 +4231,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_BUILTIN_FAST) { + TARGET(CALL_BUILTIN_FAST) { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -4260,7 +4240,6 @@ self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; /* Builtin METH_FASTCALL functions, without keywords */ - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -4318,14 +4297,8 @@ _PyCFunctionFastWithKeywords cfunc = (_PyCFunctionFastWithKeywords)(void(*)(void)) PyCFunction_GET_FUNCTION(callable); - res = cfunc( - PyCFunction_GET_SELF(callable), - args, - total_args - KWNAMES_LEN(), - kwnames - ); + res = cfunc(PyCFunction_GET_SELF(callable), args, total_args, NULL); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { @@ -4341,7 +4314,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_LEN) { + TARGET(CALL_LEN) { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -4349,7 +4322,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); /* len(o) */ int total_args = oparg; if (self_or_null != NULL) { @@ -4378,7 +4350,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_ISINSTANCE) { + TARGET(CALL_ISINSTANCE) { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -4386,7 +4358,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); /* isinstance(o, o2) */ int total_args = oparg; if (self_or_null != NULL) { @@ -4417,14 +4388,13 @@ DISPATCH(); } - TARGET(CALL_NO_KW_LIST_APPEND) { + TARGET(CALL_LIST_APPEND) { PyObject **args; PyObject *self; PyObject *callable; args = stack_pointer - oparg; self = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); assert(oparg == 1); PyInterpreterState *interp = tstate->interp; DEOPT_IF(callable != interp->callable_cache.list_append, CALL); @@ -4443,7 +4413,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) { + TARGET(CALL_METHOD_DESCRIPTOR_O) { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -4451,7 +4421,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -4511,9 +4480,8 @@ int nargs = total_args - 1; _PyCFunctionFastWithKeywords cfunc = (_PyCFunctionFastWithKeywords)(void(*)(void))meth->ml_meth; - res = cfunc(self, args + 1, nargs - KWNAMES_LEN(), kwnames); + res = cfunc(self, args + 1, nargs, NULL); assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); - kwnames = NULL; /* Free the arguments. */ for (int i = 0; i < total_args; i++) { @@ -4529,7 +4497,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS) { + TARGET(CALL_METHOD_DESCRIPTOR_NOARGS) { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -4537,7 +4505,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); assert(oparg == 0 || oparg == 1); int total_args = oparg; if (self_or_null != NULL) { @@ -4572,7 +4539,7 @@ DISPATCH(); } - TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_FAST) { + TARGET(CALL_METHOD_DESCRIPTOR_FAST) { PyObject **args; PyObject *self_or_null; PyObject *callable; @@ -4580,7 +4547,6 @@ args = stack_pointer - oparg; self_or_null = stack_pointer[-1 - oparg]; callable = stack_pointer[-2 - oparg]; - ASSERT_KWNAMES_IS_NULL(); int total_args = oparg; if (self_or_null != NULL) { args--; @@ -4613,6 +4579,105 @@ DISPATCH(); } + TARGET(INSTRUMENTED_CALL_KW) { + int is_meth = PEEK(oparg + 2) != NULL; + int total_args = oparg + is_meth; + PyObject *function = PEEK(oparg + 3); + PyObject *arg = total_args == 0 ? &_PyInstrumentation_MISSING + : PEEK(total_args + 1); + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_CALL, + frame, next_instr - 1, function, arg); + if (err) goto error; + GO_TO_INSTRUCTION(CALL_KW); + } + + TARGET(CALL_KW) { + PREDICTED(CALL_KW); + PyObject *kwnames; + PyObject **args; + PyObject *self_or_null; + PyObject *callable; + PyObject *res; + kwnames = stack_pointer[-1]; + args = stack_pointer - 1 - oparg; + self_or_null = stack_pointer[-2 - oparg]; + callable = stack_pointer[-3 - oparg]; + // oparg counts all of the args, but *not* self: + int total_args = oparg; + if (self_or_null != NULL) { + args--; + total_args++; + } + if (self_or_null == NULL && Py_TYPE(callable) == &PyMethod_Type) { + args--; + total_args++; + PyObject *self = ((PyMethodObject *)callable)->im_self; + args[0] = Py_NewRef(self); + PyObject *method = ((PyMethodObject *)callable)->im_func; + args[-1] = Py_NewRef(method); + Py_DECREF(callable); + callable = method; + } + int positional_args = total_args - (int)PyTuple_GET_SIZE(kwnames); + // Check if the call can be inlined or not + if (Py_TYPE(callable) == &PyFunction_Type && + tstate->interp->eval_frame == NULL && + ((PyFunctionObject *)callable)->vectorcall == _PyFunction_Vectorcall) + { + int code_flags = ((PyCodeObject*)PyFunction_GET_CODE(callable))->co_flags; + PyObject *locals = code_flags & CO_OPTIMIZED ? NULL : Py_NewRef(PyFunction_GET_GLOBALS(callable)); + _PyInterpreterFrame *new_frame = _PyEvalFramePushAndInit( + tstate, (PyFunctionObject *)callable, locals, + args, positional_args, kwnames + ); + Py_DECREF(kwnames); + // Manipulate stack directly since we leave using DISPATCH_INLINED(). + STACK_SHRINK(oparg + 3); + // The frame has stolen all the arguments from the stack, + // so there is no need to clean them up. + if (new_frame == NULL) { + goto error; + } + frame->return_offset = 0; + DISPATCH_INLINED(new_frame); + } + /* Callable is not a normal Python function */ + res = PyObject_Vectorcall( + callable, args, + positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET, + kwnames); + if (opcode == INSTRUMENTED_CALL_KW) { + PyObject *arg = total_args == 0 ? + &_PyInstrumentation_MISSING : args[0]; + if (res == NULL) { + _Py_call_instrumentation_exc2( + tstate, PY_MONITORING_EVENT_C_RAISE, + frame, next_instr-1, callable, arg); + } + else { + int err = _Py_call_instrumentation_2args( + tstate, PY_MONITORING_EVENT_C_RETURN, + frame, next_instr-1, callable, arg); + if (err < 0) { + Py_CLEAR(res); + } + } + } + Py_DECREF(kwnames); + assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL)); + Py_DECREF(callable); + for (int i = 0; i < total_args; i++) { + Py_DECREF(args[i]); + } + if (res == NULL) { STACK_SHRINK(oparg); goto pop_3_error; } + STACK_SHRINK(oparg); + STACK_SHRINK(2); + stack_pointer[-1] = res; + CHECK_EVAL_BREAKER(); + DISPATCH(); + } + TARGET(INSTRUMENTED_CALL_FUNCTION_EX) { GO_TO_INSTRUCTION(CALL_FUNCTION_EX); } diff --git a/Python/instrumentation.c b/Python/instrumentation.c index fee6eae..0768c82 100644 --- a/Python/instrumentation.c +++ b/Python/instrumentation.c @@ -37,6 +37,8 @@ static const int8_t EVENT_FOR_OPCODE[256] = { [INSTRUMENTED_RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN, [CALL] = PY_MONITORING_EVENT_CALL, [INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL, + [CALL_KW] = PY_MONITORING_EVENT_CALL, + [INSTRUMENTED_CALL_KW] = PY_MONITORING_EVENT_CALL, [CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, [INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL, [LOAD_SUPER_ATTR] = PY_MONITORING_EVENT_CALL, @@ -69,6 +71,7 @@ static const uint8_t DE_INSTRUMENT[256] = { [INSTRUMENTED_RETURN_VALUE] = RETURN_VALUE, [INSTRUMENTED_RETURN_CONST] = RETURN_CONST, [INSTRUMENTED_CALL] = CALL, + [INSTRUMENTED_CALL_KW] = CALL_KW, [INSTRUMENTED_CALL_FUNCTION_EX] = CALL_FUNCTION_EX, [INSTRUMENTED_YIELD_VALUE] = YIELD_VALUE, [INSTRUMENTED_JUMP_FORWARD] = JUMP_FORWARD, @@ -90,6 +93,8 @@ static const uint8_t INSTRUMENTED_OPCODES[256] = { [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE, [CALL] = INSTRUMENTED_CALL, [INSTRUMENTED_CALL] = INSTRUMENTED_CALL, + [CALL_KW] = INSTRUMENTED_CALL_KW, + [INSTRUMENTED_CALL_KW] = INSTRUMENTED_CALL_KW, [CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX, [YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE, diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h index f00eb31..bcd6ea7 100644 --- a/Python/opcode_targets.h +++ b/Python/opcode_targets.h @@ -56,6 +56,7 @@ static void *opcode_targets[256] = { &&TARGET_CALL_FUNCTION_EX, &&TARGET_CALL_INTRINSIC_1, &&TARGET_CALL_INTRINSIC_2, + &&TARGET_CALL_KW, &&TARGET_COMPARE_OP, &&TARGET_CONTAINS_OP, &&TARGET_CONVERT_VALUE, @@ -78,7 +79,6 @@ static void *opcode_targets[256] = { &&TARGET_JUMP_BACKWARD, &&TARGET_JUMP_BACKWARD_NO_INTERRUPT, &&TARGET_JUMP_FORWARD, - &&TARGET_KW_NAMES, &&TARGET_LIST_APPEND, &&TARGET_LIST_EXTEND, &&TARGET_LOAD_ATTR, @@ -161,24 +161,24 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_SUBSCR_LIST_INT, &&TARGET_BINARY_SUBSCR_STR_INT, &&TARGET_BINARY_SUBSCR_TUPLE_INT, + &&TARGET_CALL_ALLOC_AND_ENTER_INIT, &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS, &&TARGET_CALL_BUILTIN_CLASS, + &&TARGET_CALL_BUILTIN_FAST, &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS, + &&TARGET_CALL_BUILTIN_O, + &&TARGET_CALL_ISINSTANCE, + &&TARGET_CALL_LEN, + &&TARGET_CALL_LIST_APPEND, + &&TARGET_CALL_METHOD_DESCRIPTOR_FAST, &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, - &&TARGET_CALL_NO_KW_ALLOC_AND_ENTER_INIT, - &&TARGET_CALL_NO_KW_BUILTIN_FAST, - &&TARGET_CALL_NO_KW_BUILTIN_O, - &&TARGET_CALL_NO_KW_ISINSTANCE, - &&TARGET_CALL_NO_KW_LEN, - &&TARGET_CALL_NO_KW_LIST_APPEND, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_FAST, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, - &&TARGET_CALL_NO_KW_METHOD_DESCRIPTOR_O, - &&TARGET_CALL_NO_KW_STR_1, - &&TARGET_CALL_NO_KW_TUPLE_1, - &&TARGET_CALL_NO_KW_TYPE_1, + &&TARGET_CALL_METHOD_DESCRIPTOR_NOARGS, + &&TARGET_CALL_METHOD_DESCRIPTOR_O, &&TARGET_CALL_PY_EXACT_ARGS, &&TARGET_CALL_PY_WITH_DEFAULTS, + &&TARGET_CALL_STR_1, + &&TARGET_CALL_TUPLE_1, + &&TARGET_CALL_TYPE_1, &&TARGET_COMPARE_OP_FLOAT, &&TARGET_COMPARE_OP_INT, &&TARGET_COMPARE_OP_STR, @@ -235,7 +235,6 @@ static void *opcode_targets[256] = { &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode, - &&_unknown_opcode, &&TARGET_INSTRUMENTED_RESUME, &&TARGET_INSTRUMENTED_END_FOR, &&TARGET_INSTRUMENTED_END_SEND, @@ -245,6 +244,7 @@ static void *opcode_targets[256] = { &&TARGET_INSTRUMENTED_LOAD_SUPER_ATTR, &&TARGET_INSTRUMENTED_FOR_ITER, &&TARGET_INSTRUMENTED_CALL, + &&TARGET_INSTRUMENTED_CALL_KW, &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX, &&TARGET_INSTRUMENTED_INSTRUCTION, &&TARGET_INSTRUMENTED_JUMP_FORWARD, diff --git a/Python/specialize.c b/Python/specialize.c index 47e0bd7..d9b748c 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -473,7 +473,6 @@ _PyCode_Quicken(PyCodeObject *code) #define SPEC_FAIL_CALL_STR 24 #define SPEC_FAIL_CALL_CLASS_NO_VECTORCALL 25 #define SPEC_FAIL_CALL_CLASS_MUTABLE 26 -#define SPEC_FAIL_CALL_KWNAMES 27 #define SPEC_FAIL_CALL_METHOD_WRAPPER 28 #define SPEC_FAIL_CALL_OPERATOR_WRAPPER 29 #define SPEC_FAIL_CALL_INIT_NOT_SIMPLE 30 @@ -1644,24 +1643,23 @@ get_init_for_simple_managed_python_class(PyTypeObject *tp) } static int -specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, - PyObject *kwnames) +specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) { assert(PyType_Check(callable)); PyTypeObject *tp = _PyType_CAST(callable); if (tp->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) { int oparg = instr->op.arg; - if (nargs == 1 && kwnames == NULL && oparg == 1) { + if (nargs == 1 && oparg == 1) { if (tp == &PyUnicode_Type) { - instr->op.code = CALL_NO_KW_STR_1; + instr->op.code = CALL_STR_1; return 0; } else if (tp == &PyType_Type) { - instr->op.code = CALL_NO_KW_TYPE_1; + instr->op.code = CALL_TYPE_1; return 0; } else if (tp == &PyTuple_Type) { - instr->op.code = CALL_NO_KW_TUPLE_1; + instr->op.code = CALL_TUPLE_1; return 0; } } @@ -1680,13 +1678,9 @@ specialize_class_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return -1; } - if (kwnames) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); - return -1; - } _PyCallCache *cache = (_PyCallCache *)(instr + 1); write_u32(cache->func_version, tp->tp_version_tag); - _Py_SET_OPCODE(*instr, CALL_NO_KW_ALLOC_AND_ENTER_INIT); + _Py_SET_OPCODE(*instr, CALL_ALLOC_AND_ENTER_INIT); return 0; } return -1; @@ -1744,13 +1738,8 @@ meth_descr_call_fail_kind(int ml_flags) static int specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr, - int nargs, PyObject *kwnames) + int nargs) { - if (kwnames) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); - return -1; - } - switch (descr->d_method->ml_flags & (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { @@ -1759,7 +1748,7 @@ specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr, SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return -1; } - instr->op.code = CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS; + instr->op.code = CALL_METHOD_DESCRIPTOR_NOARGS; return 0; } case METH_O: { @@ -1773,14 +1762,14 @@ specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr, bool pop = (next.op.code == POP_TOP); int oparg = instr->op.arg; if ((PyObject *)descr == list_append && oparg == 1 && pop) { - instr->op.code = CALL_NO_KW_LIST_APPEND; + instr->op.code = CALL_LIST_APPEND; return 0; } - instr->op.code = CALL_NO_KW_METHOD_DESCRIPTOR_O; + instr->op.code = CALL_METHOD_DESCRIPTOR_O; return 0; } case METH_FASTCALL: { - instr->op.code = CALL_NO_KW_METHOD_DESCRIPTOR_FAST; + instr->op.code = CALL_METHOD_DESCRIPTOR_FAST; return 0; } case METH_FASTCALL | METH_KEYWORDS: { @@ -1794,7 +1783,7 @@ specialize_method_descriptor(PyMethodDescrObject *descr, _Py_CODEUNIT *instr, static int specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, - PyObject *kwnames, bool bound_method) + bool bound_method) { _PyCallCache *cache = (_PyCallCache *)(instr + 1); PyCodeObject *code = (PyCodeObject *)func->func_code; @@ -1804,10 +1793,6 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_PEP_523); return -1; } - if (kwnames) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); - return -1; - } if (kind != SIMPLE_FUNCTION) { SPECIALIZATION_FAIL(CALL, kind); return -1; @@ -1843,8 +1828,7 @@ specialize_py_call(PyFunctionObject *func, _Py_CODEUNIT *instr, int nargs, } static int -specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, - PyObject *kwnames) +specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) { if (PyCFunction_GET_FUNCTION(callable) == NULL) { return 1; @@ -1853,10 +1837,6 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, (METH_VARARGS | METH_FASTCALL | METH_NOARGS | METH_O | METH_KEYWORDS | METH_METHOD)) { case METH_O: { - if (kwnames) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); - return -1; - } if (nargs != 1) { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_WRONG_NUMBER_ARGUMENTS); return 1; @@ -1864,26 +1844,22 @@ specialize_c_call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, /* len(o) */ PyInterpreterState *interp = _PyInterpreterState_GET(); if (callable == interp->callable_cache.len) { - instr->op.code = CALL_NO_KW_LEN; + instr->op.code = CALL_LEN; return 0; } - instr->op.code = CALL_NO_KW_BUILTIN_O; + instr->op.code = CALL_BUILTIN_O; return 0; } case METH_FASTCALL: { - if (kwnames) { - SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_KWNAMES); - return -1; - } if (nargs == 2) { /* isinstance(o1, o2) */ PyInterpreterState *interp = _PyInterpreterState_GET(); if (callable == interp->callable_cache.isinstance) { - instr->op.code = CALL_NO_KW_ISINSTANCE; + instr->op.code = CALL_ISINSTANCE; return 0; } } - instr->op.code = CALL_NO_KW_BUILTIN_FAST; + instr->op.code = CALL_BUILTIN_FAST; return 0; } case METH_FASTCALL | METH_KEYWORDS: { @@ -1924,12 +1900,8 @@ call_fail_kind(PyObject *callable) #endif // Py_STATS -/* TODO: - - Specialize calling classes. -*/ void -_Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, - PyObject *kwnames) +_Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs) { assert(ENABLE_SPECIALIZATION); assert(_PyOpcode_Caches[CALL] == INLINE_CACHE_ENTRIES_CALL); @@ -1937,25 +1909,23 @@ _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs, _PyCallCache *cache = (_PyCallCache *)(instr + 1); int fail; if (PyCFunction_CheckExact(callable)) { - fail = specialize_c_call(callable, instr, nargs, kwnames); + fail = specialize_c_call(callable, instr, nargs); } else if (PyFunction_Check(callable)) { - fail = specialize_py_call((PyFunctionObject *)callable, instr, nargs, - kwnames, false); + fail = specialize_py_call((PyFunctionObject *)callable, instr, nargs, false); } else if (PyType_Check(callable)) { - fail = specialize_class_call(callable, instr, nargs, kwnames); + fail = specialize_class_call(callable, instr, nargs); } else if (Py_IS_TYPE(callable, &PyMethodDescr_Type)) { - fail = specialize_method_descriptor((PyMethodDescrObject *)callable, - instr, nargs, kwnames); + fail = specialize_method_descriptor((PyMethodDescrObject *)callable, instr, nargs); } else if (PyMethod_Check(callable)) { PyObject *func = ((PyMethodObject *)callable)->im_func; if (PyFunction_Check(func)) { - fail = specialize_py_call((PyFunctionObject *)func, - instr, nargs+1, kwnames, true); - } else { + fail = specialize_py_call((PyFunctionObject *)func, instr, nargs+1, true); + } + else { SPECIALIZATION_FAIL(CALL, SPEC_FAIL_CALL_BOUND_METHOD); fail = -1; } @@ -2491,7 +2461,7 @@ success: } /* Code init cleanup. - * CALL_NO_KW_ALLOC_AND_ENTER_INIT will set up + * CALL_ALLOC_AND_ENTER_INIT will set up * the frame to execute the EXIT_INIT_CHECK * instruction. * Ends with a RESUME so that it is not traced. |