Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 47dd2f9

Browse files
msullivanmethane
authored andcommitted
bpo-37017: PyObject_CallMethodObjArgs uses LOAD_METHOD optimization (GH-13516)
Update PyObject_CallMethodObjArgs and _PyObject_CallMethodIdObjArgs to use _PyObject_GetMethod to avoid creating a bound method object in many cases. On a microbenchmark of PyObject_CallMethodObjArgs calling a method on an interpreted Python class, this optimization resulted in a 1.7x speedup.
1 parent 7114c65 commit 47dd2f9

2 files changed

Lines changed: 33 additions & 16 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Update :c:func:`PyObject_CallMethodObjArgs` and ``_PyObject_CallMethodIdObjArgs``
2+
to use ``_PyObject_GetMethod`` to avoid creating a bound method object in many
3+
cases.
4+
Patch by Michael J. Sullivan.

Objects/call.c

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,7 +1159,7 @@ _PyObject_CallMethodId_SizeT(PyObject *obj, _Py_Identifier *name,
11591159
/* --- Call with "..." arguments ---------------------------------- */
11601160

11611161
static PyObject *
1162-
object_vacall(PyObject *callable, va_list vargs)
1162+
object_vacall(PyObject *base, PyObject *callable, va_list vargs)
11631163
{
11641164
PyObject *small_stack[_PY_FASTCALL_SMALL_STACK];
11651165
PyObject **stack;
@@ -1174,7 +1174,7 @@ object_vacall(PyObject *callable, va_list vargs)
11741174

11751175
/* Count the number of arguments */
11761176
va_copy(countva, vargs);
1177-
nargs = 0;
1177+
nargs = base ? 1 : 0;
11781178
while (1) {
11791179
PyObject *arg = va_arg(countva, PyObject *);
11801180
if (arg == NULL) {
@@ -1196,7 +1196,12 @@ object_vacall(PyObject *callable, va_list vargs)
11961196
}
11971197
}
11981198

1199-
for (i = 0; i < nargs; ++i) {
1199+
i = 0;
1200+
if (base) {
1201+
stack[i++] = base;
1202+
}
1203+
1204+
for (; i < nargs; ++i) {
12001205
stack[i] = va_arg(vargs, PyObject *);
12011206
}
12021207

@@ -1210,23 +1215,26 @@ object_vacall(PyObject *callable, va_list vargs)
12101215
}
12111216

12121217

1218+
/* Private API for the LOAD_METHOD opcode. */
1219+
extern int _PyObject_GetMethod(PyObject *, PyObject *, PyObject **);
1220+
12131221
PyObject *
1214-
PyObject_CallMethodObjArgs(PyObject *callable, PyObject *name, ...)
1222+
PyObject_CallMethodObjArgs(PyObject *obj, PyObject *name, ...)
12151223
{
1216-
va_list vargs;
1217-
PyObject *result;
1218-
1219-
if (callable == NULL || name == NULL) {
1224+
if (obj == NULL || name == NULL) {
12201225
return null_error();
12211226
}
12221227

1223-
callable = PyObject_GetAttr(callable, name);
1228+
PyObject *callable = NULL;
1229+
int is_method = _PyObject_GetMethod(obj, name, &callable);
12241230
if (callable == NULL) {
12251231
return NULL;
12261232
}
1233+
obj = is_method ? obj : NULL;
12271234

1235+
va_list vargs;
12281236
va_start(vargs, name);
1229-
result = object_vacall(callable, vargs);
1237+
PyObject *result = object_vacall(obj, callable, vargs);
12301238
va_end(vargs);
12311239

12321240
Py_DECREF(callable);
@@ -1238,20 +1246,25 @@ PyObject *
12381246
_PyObject_CallMethodIdObjArgs(PyObject *obj,
12391247
struct _Py_Identifier *name, ...)
12401248
{
1241-
va_list vargs;
1242-
PyObject *callable, *result;
1243-
12441249
if (obj == NULL || name == NULL) {
12451250
return null_error();
12461251
}
12471252

1248-
callable = _PyObject_GetAttrId(obj, name);
1253+
PyObject *oname = _PyUnicode_FromId(name); /* borrowed */
1254+
if (!oname) {
1255+
return NULL;
1256+
}
1257+
1258+
PyObject *callable = NULL;
1259+
int is_method = _PyObject_GetMethod(obj, oname, &callable);
12491260
if (callable == NULL) {
12501261
return NULL;
12511262
}
1263+
obj = is_method ? obj : NULL;
12521264

1265+
va_list vargs;
12531266
va_start(vargs, name);
1254-
result = object_vacall(callable, vargs);
1267+
PyObject *result = object_vacall(obj, callable, vargs);
12551268
va_end(vargs);
12561269

12571270
Py_DECREF(callable);
@@ -1266,7 +1279,7 @@ PyObject_CallFunctionObjArgs(PyObject *callable, ...)
12661279
PyObject *result;
12671280

12681281
va_start(vargs, callable);
1269-
result = object_vacall(callable, vargs);
1282+
result = object_vacall(NULL, callable, vargs);
12701283
va_end(vargs);
12711284

12721285
return result;

0 commit comments

Comments
 (0)