summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Include/internal/pycore_opcode_metadata.h10
-rw-r--r--Python/bytecodes.c30
-rw-r--r--Python/ceval.c4
-rw-r--r--Python/ceval_macros.h2
-rw-r--r--Python/executor_cases.c.h329
-rw-r--r--Python/generated_cases.c.h30
-rw-r--r--Tools/cases_generator/generate_cases.py14
7 files changed, 385 insertions, 34 deletions
diff --git a/Include/internal/pycore_opcode_metadata.h b/Include/internal/pycore_opcode_metadata.h
index 3b2eab2..028736e 100644
--- a/Include/internal/pycore_opcode_metadata.h
+++ b/Include/internal/pycore_opcode_metadata.h
@@ -1309,7 +1309,17 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[OPCODE_MACRO_EXPAN
[GET_YIELD_FROM_ITER] = { .nuops = 1, .uops = { { GET_YIELD_FROM_ITER, 0, 0 } } },
[WITH_EXCEPT_START] = { .nuops = 1, .uops = { { WITH_EXCEPT_START, 0, 0 } } },
[PUSH_EXC_INFO] = { .nuops = 1, .uops = { { PUSH_EXC_INFO, 0, 0 } } },
+ [CALL_NO_KW_TYPE_1] = { .nuops = 1, .uops = { { CALL_NO_KW_TYPE_1, 0, 0 } } },
+ [CALL_NO_KW_STR_1] = { .nuops = 1, .uops = { { CALL_NO_KW_STR_1, 0, 0 } } },
+ [CALL_NO_KW_TUPLE_1] = { .nuops = 1, .uops = { { CALL_NO_KW_TUPLE_1, 0, 0 } } },
[EXIT_INIT_CHECK] = { .nuops = 1, .uops = { { EXIT_INIT_CHECK, 0, 0 } } },
+ [CALL_NO_KW_BUILTIN_O] = { .nuops = 1, .uops = { { CALL_NO_KW_BUILTIN_O, 0, 0 } } },
+ [CALL_NO_KW_BUILTIN_FAST] = { .nuops = 1, .uops = { { CALL_NO_KW_BUILTIN_FAST, 0, 0 } } },
+ [CALL_NO_KW_LEN] = { .nuops = 1, .uops = { { CALL_NO_KW_LEN, 0, 0 } } },
+ [CALL_NO_KW_ISINSTANCE] = { .nuops = 1, .uops = { { CALL_NO_KW_ISINSTANCE, 0, 0 } } },
+ [CALL_NO_KW_METHOD_DESCRIPTOR_O] = { .nuops = 1, .uops = { { CALL_NO_KW_METHOD_DESCRIPTOR_O, 0, 0 } } },
+ [CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 1, .uops = { { CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, 0, 0 } } },
+ [CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { .nuops = 1, .uops = { { CALL_NO_KW_METHOD_DESCRIPTOR_FAST, 0, 0 } } },
[MAKE_FUNCTION] = { .nuops = 1, .uops = { { MAKE_FUNCTION, 0, 0 } } },
[SET_FUNCTION_ATTRIBUTE] = { .nuops = 1, .uops = { { SET_FUNCTION_ATTRIBUTE, 0, 0 } } },
[BUILD_SLICE] = { .nuops = 1, .uops = { { BUILD_SLICE, 0, 0 } } },
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 3c3992c..652372c 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -2776,7 +2776,7 @@ dummy_func(
}
inst(KW_NAMES, (--)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS));
kwnames = GETITEM(FRAME_CO_CONSTS, oparg);
}
@@ -2927,7 +2927,7 @@ dummy_func(
}
inst(CALL_PY_EXACT_ARGS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
DEOPT_IF(tstate->interp->eval_frame, CALL);
int is_meth = method != NULL;
int argcount = oparg;
@@ -2955,7 +2955,7 @@ dummy_func(
}
inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, method, callable, args[oparg] -- unused)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
DEOPT_IF(tstate->interp->eval_frame, CALL);
int is_meth = method != NULL;
int argcount = oparg;
@@ -2993,7 +2993,7 @@ dummy_func(
}
inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
PyObject *obj = args[0];
@@ -3005,7 +3005,7 @@ dummy_func(
}
inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL);
@@ -3019,7 +3019,7 @@ dummy_func(
}
inst(CALL_NO_KW_TUPLE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL);
@@ -3038,7 +3038,7 @@ dummy_func(
* 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 == NULL);
+ ASSERT_KWNAMES_IS_NULL();
_PyCallCache *cache = (_PyCallCache *)next_instr;
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(!PyType_Check(callable), CALL);
@@ -3122,7 +3122,7 @@ dummy_func(
inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
/* Builtin METH_O functions */
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
@@ -3153,7 +3153,7 @@ dummy_func(
inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
/* Builtin METH_FASTCALL functions, without keywords */
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
@@ -3222,7 +3222,7 @@ dummy_func(
}
inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
/* len(o) */
int is_meth = method != NULL;
int total_args = oparg;
@@ -3249,7 +3249,7 @@ dummy_func(
}
inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
/* isinstance(o, o2) */
int is_meth = method != NULL;
int total_args = oparg;
@@ -3279,7 +3279,7 @@ dummy_func(
// This is secretly a super-instruction
inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
assert(method != NULL);
PyInterpreterState *interp = _PyInterpreterState_GET();
@@ -3299,7 +3299,7 @@ dummy_func(
}
inst(CALL_NO_KW_METHOD_DESCRIPTOR_O, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
@@ -3365,7 +3365,7 @@ dummy_func(
}
inst(CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 0 || oparg == 1);
int is_meth = method != NULL;
int total_args = oparg;
@@ -3397,7 +3397,7 @@ dummy_func(
}
inst(CALL_NO_KW_METHOD_DESCRIPTOR_FAST, (unused/1, unused/2, method, unused, args[oparg] -- res)) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
diff --git a/Python/ceval.c b/Python/ceval.c
index d6c72fa..f13ba98 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -2706,6 +2706,9 @@ void Py_LeaveRecursiveCall(void)
///////////////////// Experimental UOp Interpreter /////////////////////
+#undef ASSERT_KWNAMES_IS_NULL
+#define ASSERT_KWNAMES_IS_NULL() (void)0
+
#undef DEOPT_IF
#define DEOPT_IF(COND, INSTNAME) \
if ((COND)) { \
@@ -2746,6 +2749,7 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
int opcode;
uint64_t operand;
int oparg;
+
for (;;) {
opcode = self->trace[pc].opcode;
operand = self->trace[pc].operand;
diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h
index 72800aa..874bd45 100644
--- a/Python/ceval_macros.h
+++ b/Python/ceval_macros.h
@@ -349,3 +349,5 @@ static const convertion_func_ptr CONVERSION_FUNCTIONS[4] = {
[FVC_REPR] = PyObject_Repr,
[FVC_ASCII] = PyObject_ASCII
};
+
+#define ASSERT_KWNAMES_IS_NULL() assert(kwnames == NULL)
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index ae21ffa..d85e23b 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -1904,6 +1904,68 @@
break;
}
+ case CALL_NO_KW_TYPE_1: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *callable = stack_pointer[-(1 + oparg)];
+ PyObject *null = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ ASSERT_KWNAMES_IS_NULL();
+ assert(oparg == 1);
+ DEOPT_IF(null != NULL, CALL);
+ PyObject *obj = args[0];
+ DEOPT_IF(callable != (PyObject *)&PyType_Type, CALL);
+ STAT_INC(CALL, hit);
+ res = Py_NewRef(Py_TYPE(obj));
+ Py_DECREF(obj);
+ Py_DECREF(&PyType_Type); // I.e., callable
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ break;
+ }
+
+ case CALL_NO_KW_STR_1: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *callable = stack_pointer[-(1 + oparg)];
+ PyObject *null = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ ASSERT_KWNAMES_IS_NULL();
+ assert(oparg == 1);
+ DEOPT_IF(null != NULL, CALL);
+ DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL);
+ STAT_INC(CALL, hit);
+ PyObject *arg = args[0];
+ res = PyObject_Str(arg);
+ Py_DECREF(arg);
+ Py_DECREF(&PyUnicode_Type); // I.e., callable
+ if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ break;
+ }
+
+ case CALL_NO_KW_TUPLE_1: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *callable = stack_pointer[-(1 + oparg)];
+ PyObject *null = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ ASSERT_KWNAMES_IS_NULL();
+ assert(oparg == 1);
+ DEOPT_IF(null != NULL, CALL);
+ DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL);
+ STAT_INC(CALL, hit);
+ PyObject *arg = args[0];
+ res = PySequence_Tuple(arg);
+ Py_DECREF(arg);
+ Py_DECREF(&PyTuple_Type); // I.e., tuple
+ if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ break;
+ }
+
case EXIT_INIT_CHECK: {
PyObject *should_be_none = stack_pointer[-1];
assert(STACK_LEVEL() == 2);
@@ -1917,6 +1979,273 @@
break;
}
+ case CALL_NO_KW_BUILTIN_O: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *callable = stack_pointer[-(1 + oparg)];
+ PyObject *method = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ /* Builtin METH_O functions */
+ ASSERT_KWNAMES_IS_NULL();
+ int is_meth = method != NULL;
+ int total_args = oparg;
+ if (is_meth) {
+ callable = method;
+ args--;
+ total_args++;
+ }
+ DEOPT_IF(total_args != 1, CALL);
+ DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
+ DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_O, CALL);
+ STAT_INC(CALL, hit);
+ PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
+ // This is slower but CPython promises to check all non-vectorcall
+ // function calls.
+ if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) {
+ goto error;
+ }
+ PyObject *arg = args[0];
+ res = _PyCFunction_TrampolineCall(cfunc, PyCFunction_GET_SELF(callable), arg);
+ _Py_LeaveRecursiveCallTstate(tstate);
+ assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
+
+ Py_DECREF(arg);
+ Py_DECREF(callable);
+ if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ break;
+ }
+
+ case CALL_NO_KW_BUILTIN_FAST: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *callable = stack_pointer[-(1 + oparg)];
+ PyObject *method = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ /* Builtin METH_FASTCALL functions, without keywords */
+ ASSERT_KWNAMES_IS_NULL();
+ int is_meth = method != NULL;
+ int total_args = oparg;
+ if (is_meth) {
+ callable = method;
+ args--;
+ total_args++;
+ }
+ DEOPT_IF(!PyCFunction_CheckExact(callable), CALL);
+ DEOPT_IF(PyCFunction_GET_FLAGS(callable) != METH_FASTCALL, CALL);
+ STAT_INC(CALL, hit);
+ PyCFunction cfunc = PyCFunction_GET_FUNCTION(callable);
+ /* res = func(self, args, nargs) */
+ res = ((_PyCFunctionFast)(void(*)(void))cfunc)(
+ PyCFunction_GET_SELF(callable),
+ args,
+ total_args);
+ 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; }
+ /* Not deopting because this doesn't mean our optimization was
+ wrong. `res` can be NULL for valid reasons. Eg. getattr(x,
+ 'invalid'). In those cases an exception is set, so we must
+ handle it.
+ */
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ break;
+ }
+
+ case CALL_NO_KW_LEN: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *callable = stack_pointer[-(1 + oparg)];
+ PyObject *method = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ ASSERT_KWNAMES_IS_NULL();
+ /* len(o) */
+ int is_meth = method != NULL;
+ int total_args = oparg;
+ if (is_meth) {
+ callable = method;
+ args--;
+ total_args++;
+ }
+ DEOPT_IF(total_args != 1, CALL);
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ DEOPT_IF(callable != interp->callable_cache.len, CALL);
+ STAT_INC(CALL, hit);
+ PyObject *arg = args[0];
+ Py_ssize_t len_i = PyObject_Length(arg);
+ if (len_i < 0) {
+ goto error;
+ }
+ res = PyLong_FromSsize_t(len_i);
+ assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
+
+ Py_DECREF(callable);
+ Py_DECREF(arg);
+ if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ break;
+ }
+
+ case CALL_NO_KW_ISINSTANCE: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *callable = stack_pointer[-(1 + oparg)];
+ PyObject *method = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ ASSERT_KWNAMES_IS_NULL();
+ /* isinstance(o, o2) */
+ int is_meth = method != NULL;
+ int total_args = oparg;
+ if (is_meth) {
+ callable = method;
+ args--;
+ total_args++;
+ }
+ DEOPT_IF(total_args != 2, CALL);
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ DEOPT_IF(callable != interp->callable_cache.isinstance, CALL);
+ STAT_INC(CALL, hit);
+ PyObject *cls = args[1];
+ PyObject *inst = args[0];
+ int retval = PyObject_IsInstance(inst, cls);
+ if (retval < 0) {
+ goto error;
+ }
+ res = PyBool_FromLong(retval);
+ assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
+
+ Py_DECREF(inst);
+ Py_DECREF(cls);
+ Py_DECREF(callable);
+ if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ break;
+ }
+
+ case CALL_NO_KW_METHOD_DESCRIPTOR_O: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *method = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ ASSERT_KWNAMES_IS_NULL();
+ int is_meth = method != NULL;
+ int total_args = oparg;
+ if (is_meth) {
+ args--;
+ total_args++;
+ }
+ PyMethodDescrObject *callable =
+ (PyMethodDescrObject *)PEEK(total_args + 1);
+ DEOPT_IF(total_args != 2, CALL);
+ DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = callable->d_method;
+ DEOPT_IF(meth->ml_flags != METH_O, CALL);
+ PyObject *arg = args[1];
+ PyObject *self = args[0];
+ DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ STAT_INC(CALL, hit);
+ PyCFunction cfunc = meth->ml_meth;
+ // This is slower but CPython promises to check all non-vectorcall
+ // function calls.
+ if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) {
+ goto error;
+ }
+ res = _PyCFunction_TrampolineCall(cfunc, self, arg);
+ _Py_LeaveRecursiveCallTstate(tstate);
+ assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
+ Py_DECREF(self);
+ Py_DECREF(arg);
+ Py_DECREF(callable);
+ if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ break;
+ }
+
+ case CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *method = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ ASSERT_KWNAMES_IS_NULL();
+ assert(oparg == 0 || oparg == 1);
+ int is_meth = method != NULL;
+ int total_args = oparg;
+ if (is_meth) {
+ args--;
+ total_args++;
+ }
+ DEOPT_IF(total_args != 1, CALL);
+ PyMethodDescrObject *callable = (PyMethodDescrObject *)SECOND();
+ DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = callable->d_method;
+ PyObject *self = args[0];
+ DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ DEOPT_IF(meth->ml_flags != METH_NOARGS, CALL);
+ STAT_INC(CALL, hit);
+ PyCFunction cfunc = meth->ml_meth;
+ // This is slower but CPython promises to check all non-vectorcall
+ // function calls.
+ if (_Py_EnterRecursiveCallTstate(tstate, " while calling a Python object")) {
+ goto error;
+ }
+ res = _PyCFunction_TrampolineCall(cfunc, self, NULL);
+ _Py_LeaveRecursiveCallTstate(tstate);
+ assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
+ Py_DECREF(self);
+ Py_DECREF(callable);
+ if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
+ STACK_SHRINK(oparg);
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ break;
+ }
+
+ case CALL_NO_KW_METHOD_DESCRIPTOR_FAST: {
+ PyObject **args = (stack_pointer - oparg);
+ PyObject *method = stack_pointer[-(2 + oparg)];
+ PyObject *res;
+ ASSERT_KWNAMES_IS_NULL();
+ int is_meth = method != NULL;
+ int total_args = oparg;
+ if (is_meth) {
+ args--;
+ total_args++;
+ }
+ PyMethodDescrObject *callable =
+ (PyMethodDescrObject *)PEEK(total_args + 1);
+ /* Builtin METH_FASTCALL methods, without keywords */
+ DEOPT_IF(!Py_IS_TYPE(callable, &PyMethodDescr_Type), CALL);
+ PyMethodDef *meth = callable->d_method;
+ DEOPT_IF(meth->ml_flags != METH_FASTCALL, CALL);
+ PyObject *self = args[0];
+ DEOPT_IF(!Py_IS_TYPE(self, callable->d_common.d_type), CALL);
+ STAT_INC(CALL, hit);
+ _PyCFunctionFast cfunc =
+ (_PyCFunctionFast)(void(*)(void))meth->ml_meth;
+ int nargs = total_args - 1;
+ res = cfunc(self, args + 1, nargs);
+ assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
+ /* Clear the stack of 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;
+ break;
+ }
+
case MAKE_FUNCTION: {
PyObject *codeobj = stack_pointer[-1];
PyObject *func;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 392914c..1fd7671 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -3462,7 +3462,7 @@
}
TARGET(KW_NAMES) {
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg < PyTuple_GET_SIZE(FRAME_CO_CONSTS));
kwnames = GETITEM(FRAME_CO_CONSTS, oparg);
DISPATCH();
@@ -3599,7 +3599,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
uint32_t func_version = read_u32(&next_instr[1].cache);
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
DEOPT_IF(tstate->interp->eval_frame, CALL);
int is_meth = method != NULL;
int argcount = oparg;
@@ -3631,7 +3631,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
uint32_t func_version = read_u32(&next_instr[1].cache);
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
DEOPT_IF(tstate->interp->eval_frame, CALL);
int is_meth = method != NULL;
int argcount = oparg;
@@ -3673,7 +3673,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *null = stack_pointer[-(2 + oparg)];
PyObject *res;
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
PyObject *obj = args[0];
@@ -3694,7 +3694,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *null = stack_pointer[-(2 + oparg)];
PyObject *res;
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL);
@@ -3717,7 +3717,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *null = stack_pointer[-(2 + oparg)];
PyObject *res;
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(callable != (PyObject *)&PyTuple_Type, CALL);
@@ -3744,7 +3744,7 @@
* 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 == NULL);
+ ASSERT_KWNAMES_IS_NULL();
_PyCallCache *cache = (_PyCallCache *)next_instr;
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(!PyType_Check(callable), CALL);
@@ -3844,7 +3844,7 @@
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
/* Builtin METH_O functions */
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
@@ -3884,7 +3884,7 @@
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
/* Builtin METH_FASTCALL functions, without keywords */
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
@@ -3971,7 +3971,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
/* len(o) */
int is_meth = method != NULL;
int total_args = oparg;
@@ -4007,7 +4007,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
/* isinstance(o, o2) */
int is_meth = method != NULL;
int total_args = oparg;
@@ -4044,7 +4044,7 @@
PyObject **args = (stack_pointer - oparg);
PyObject *self = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 1);
assert(method != NULL);
PyInterpreterState *interp = _PyInterpreterState_GET();
@@ -4067,7 +4067,7 @@
PyObject **args = (stack_pointer - oparg);
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
@@ -4149,7 +4149,7 @@
PyObject **args = (stack_pointer - oparg);
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
assert(oparg == 0 || oparg == 1);
int is_meth = method != NULL;
int total_args = oparg;
@@ -4189,7 +4189,7 @@
PyObject **args = (stack_pointer - oparg);
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- assert(kwnames == NULL);
+ ASSERT_KWNAMES_IS_NULL();
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
diff --git a/Tools/cases_generator/generate_cases.py b/Tools/cases_generator/generate_cases.py
index a0a8b8c..112f29a 100644
--- a/Tools/cases_generator/generate_cases.py
+++ b/Tools/cases_generator/generate_cases.py
@@ -408,27 +408,31 @@ class Instruction:
def is_viable_uop(self) -> bool:
"""Whether this instruction is viable as a uop."""
+ dprint: typing.Callable[..., None] = lambda *args, **kwargs: None
+ # if self.name.startswith("CALL"):
+ # dprint = print
+
if self.name == "EXIT_TRACE":
return True # This has 'return frame' but it's okay
if self.always_exits:
- # print(f"Skipping {self.name} because it always exits")
+ dprint(f"Skipping {self.name} because it always exits")
return False
if self.instr_flags.HAS_ARG_FLAG:
# If the instruction uses oparg, it cannot use any caches
if self.active_caches:
- # print(f"Skipping {self.name} because it uses oparg and caches")
+ dprint(f"Skipping {self.name} because it uses oparg and caches")
return False
else:
# If it doesn't use oparg, it can have one cache entry
if len(self.active_caches) > 1:
- # print(f"Skipping {self.name} because it has >1 cache entries")
+ dprint(f"Skipping {self.name} because it has >1 cache entries")
return False
res = True
for forbidden in FORBIDDEN_NAMES_IN_UOPS:
# NOTE: To disallow unspecialized uops, use
# if variable_used(self.inst, forbidden):
if variable_used_unspecialized(self.inst, forbidden):
- # print(f"Skipping {self.name} because it uses {forbidden}")
+ dprint(f"Skipping {self.name} because it uses {forbidden}")
res = False
return res
@@ -1499,6 +1503,8 @@ class Analyzer:
with self.out.block(f"case {thing.name}:"):
instr.write(self.out, tier=TIER_TWO)
self.out.emit("break;")
+ # elif instr.kind != "op":
+ # print(f"NOTE: {thing.name} is not a viable uop")
case parser.Macro():
pass
case parser.Pseudo():