Skip to content

Commit 60aaed7

Browse files
committed
optimize _CALL_BUILTIN_FAST_WITH_KEYWORDS
1 parent 70b86e7 commit 60aaed7

12 files changed

Lines changed: 92 additions & 58 deletions

File tree

Include/internal/pycore_ceval.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,7 @@ _Py_BuiltinCallFast_StackRef(
439439
int total_args);
440440

441441
PyAPI_FUNC(PyObject *)
442-
_Py_BuiltinCallFastWithKeywords_StackRefSteal(
442+
_Py_BuiltinCallFastWithKeywords_StackRef(
443443
_PyStackRef callable,
444444
_PyStackRef *arguments,
445445
int total_args);

Include/internal/pycore_opcode_metadata.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_ids.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_capi/test_opt.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2746,7 +2746,12 @@ def test_call_builtin_fast_with_keywords(self):
27462746
def testfunc(n):
27472747
x = 0
27482748
for _ in range(n):
2749+
# _CALL_BUILTIN_FAST_WITH_KEYWORDS: 1 _POP_TOP_NOP, 1 POP_TOP
2750+
# _LIST_EXTEND: 1 _POP_TOP_NOP,
27492751
y = sorted([3, 1, 2])
2752+
2753+
# _BINARY_OP_SUBSCR_LIST_INT: 2 _POP_TOP_NOP
2754+
# _BINARY_OP_ADD_INT: 1 _POP_TOP_NOP
27502755
x += y[0]
27512756
return x
27522757

@@ -2756,6 +2761,8 @@ def testfunc(n):
27562761
uops = get_opnames(ex)
27572762
self.assertIn("_CALL_BUILTIN_FAST_WITH_KEYWORDS", uops)
27582763
self.assertNotIn("_GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS", uops)
2764+
self.assertGreaterEqual(count_ops(ex, "_POP_TOP_NOP"), 5)
2765+
self.assertGreaterEqual(count_ops(ex, "_POP_TOP"), 3)
27592766

27602767
def test_call_method_descriptor_o(self):
27612768
def testfunc(n):

Modules/_testinternalcapi/test_cases.c.h

Lines changed: 23 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/bytecodes.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4689,7 +4689,7 @@ dummy_func(
46894689
EXIT_IF(PyCFunction_GET_FLAGS(callable_o) != (METH_FASTCALL | METH_KEYWORDS));
46904690
}
46914691

4692-
op(_CALL_BUILTIN_FAST_WITH_KEYWORDS, (callable, self_or_null, args[oparg] -- res)) {
4692+
op(_CALL_BUILTIN_FAST_WITH_KEYWORDS, (callable, self_or_null, args[oparg] -- callable, self_or_null, args[oparg])) {
46934693
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */
46944694
int total_args = oparg;
46954695
_PyStackRef *arguments = args;
@@ -4698,12 +4698,13 @@ dummy_func(
46984698
total_args++;
46994699
}
47004700
STAT_INC(CALL, hit);
4701-
PyObject *res_o = _Py_BuiltinCallFastWithKeywords_StackRefSteal(callable, arguments, total_args);
4702-
DEAD(args);
4703-
DEAD(self_or_null);
4704-
DEAD(callable);
4705-
ERROR_IF(res_o == NULL);
4706-
res = PyStackRef_FromPyObjectSteal(res_o);
4701+
PyObject *res_o = _Py_BuiltinCallFastWithKeywords_StackRef(callable, arguments, total_args);
4702+
if (res_o == NULL) {
4703+
ERROR_NO_POP();
4704+
}
4705+
_PyStackRef temp = callable;
4706+
callable = PyStackRef_FromPyObjectSteal(res_o);
4707+
PyStackRef_CLOSE(temp);
47074708
}
47084709

47094710
macro(CALL_BUILTIN_FAST_WITH_KEYWORDS) =
@@ -4712,6 +4713,8 @@ dummy_func(
47124713
unused/2 +
47134714
_GUARD_CALLABLE_BUILTIN_FAST_WITH_KEYWORDS +
47144715
_CALL_BUILTIN_FAST_WITH_KEYWORDS +
4716+
_POP_TOP_OPARG +
4717+
POP_TOP +
47154718
_CHECK_PERIODIC_AT_END;
47164719

47174720
macro(CALL_LEN) =

Python/ceval.c

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -832,32 +832,22 @@ _Py_BuiltinCallFast_StackRef(
832832
}
833833

834834
PyObject *
835-
_Py_BuiltinCallFastWithKeywords_StackRefSteal(
835+
_Py_BuiltinCallFastWithKeywords_StackRef(
836836
_PyStackRef callable,
837837
_PyStackRef *arguments,
838838
int total_args)
839839
{
840840
PyObject *res;
841841
STACKREFS_TO_PYOBJECTS(arguments, total_args, args_o);
842842
if (CONVERSION_FAILED(args_o)) {
843-
res = NULL;
844-
goto cleanup;
843+
return NULL;
845844
}
846845
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
847846
PyCFunctionFastWithKeywords cfunc =
848847
_PyCFunctionFastWithKeywords_CAST(PyCFunction_GET_FUNCTION(callable_o));
849848
res = cfunc(PyCFunction_GET_SELF(callable_o), args_o, total_args, NULL);
850849
STACKREFS_TO_PYOBJECTS_CLEANUP(args_o);
851850
assert((res != NULL) ^ (PyErr_Occurred() != NULL));
852-
cleanup:
853-
// arguments is a pointer into the GC visible stack,
854-
// so we must NULL out values as we clear them.
855-
for (int i = total_args-1; i >= 0; i--) {
856-
_PyStackRef tmp = arguments[i];
857-
arguments[i] = PyStackRef_NULL;
858-
PyStackRef_CLOSE(tmp);
859-
}
860-
PyStackRef_CLOSE(callable);
861851
return res;
862852
}
863853

Python/executor_cases.c.h

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 23 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)