Skip to content

Commit dac5ba7

Browse files
bpo-30509: Optimize and clean up calling type slots.
1 parent a4fcc37 commit dac5ba7

1 file changed

Lines changed: 84 additions & 73 deletions

File tree

Objects/typeobject.c

Lines changed: 84 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,7 +1429,7 @@ _PyObject_LookupSpecial(PyObject *self, _Py_Identifier *attrid)
14291429
return res;
14301430
}
14311431

1432-
static PyObject *
1432+
Py_LOCAL_INLINE(PyObject *)
14331433
lookup_maybe_method(PyObject *self, _Py_Identifier *attrid, int *unbound)
14341434
{
14351435
PyObject *res = _PyType_LookupId(Py_TYPE(self), attrid);
@@ -1455,7 +1455,7 @@ lookup_maybe_method(PyObject *self, _Py_Identifier *attrid, int *unbound)
14551455
return res;
14561456
}
14571457

1458-
static PyObject *
1458+
Py_LOCAL_INLINE(PyObject *)
14591459
lookup_method(PyObject *self, _Py_Identifier *attrid, int *unbound)
14601460
{
14611461
PyObject *res = lookup_maybe_method(self, attrid, unbound);
@@ -1465,65 +1465,103 @@ lookup_method(PyObject *self, _Py_Identifier *attrid, int *unbound)
14651465
return res;
14661466
}
14671467

1468-
static PyObject*
1469-
call_unbound(int unbound, PyObject *func, PyObject *self,
1470-
PyObject **args, Py_ssize_t nargs)
1468+
Py_LOCAL_INLINE(PyObject *)
1469+
call_unbound_noarg(int unbound, PyObject *func, PyObject *self)
14711470
{
14721471
if (unbound) {
1473-
return _PyObject_FastCall_Prepend(func, self, args, nargs);
1472+
PyObject *args[1] = {self};
1473+
return _PyObject_FastCall(func, args, 1);
14741474
}
14751475
else {
1476-
return _PyObject_FastCall(func, args, nargs);
1476+
return _PyObject_CallNoArg(func);
14771477
}
14781478
}
14791479

1480-
static PyObject*
1481-
call_unbound_noarg(int unbound, PyObject *func, PyObject *self)
1480+
Py_LOCAL_INLINE(PyObject *)
1481+
call_unbound_onearg(int unbound, PyObject *func, PyObject *self, PyObject *arg)
14821482
{
14831483
if (unbound) {
1484-
PyObject *args[1] = {self};
1485-
return _PyObject_FastCall(func, args, 1);
1484+
PyObject *args[2] = {self, arg};
1485+
return _PyObject_FastCall(func, args, 2);
14861486
}
14871487
else {
1488-
return _PyObject_CallNoArg(func);
1488+
PyObject *args[1] = {arg};
1489+
return _PyObject_FastCall(func, args, 1);
14891490
}
14901491
}
14911492

1492-
/* A variation of PyObject_CallMethod* that uses lookup_maybe_method()
1493+
/* Variations of PyObject_CallMethod* that use lookup_maybe_method()
14931494
instead of PyObject_GetAttrString(). */
14941495
static PyObject *
1495-
call_method(PyObject *obj, _Py_Identifier *name,
1496-
PyObject **args, Py_ssize_t nargs)
1496+
call_method_noarg(PyObject *self, _Py_Identifier *name)
14971497
{
14981498
int unbound;
14991499
PyObject *func, *retval;
15001500

1501-
func = lookup_method(obj, name, &unbound);
1501+
func = lookup_method(self, name, &unbound);
15021502
if (func == NULL)
15031503
return NULL;
15041504

1505-
retval = call_unbound(unbound, func, obj, args, nargs);
1505+
retval = call_unbound_noarg(unbound, func, self);
15061506
Py_DECREF(func);
15071507
return retval;
15081508
}
15091509

1510-
/* Clone of call_method() that returns NotImplemented when the lookup fails. */
1510+
static PyObject *
1511+
call_method_onearg(PyObject *self, _Py_Identifier *name, PyObject *arg)
1512+
{
1513+
int unbound;
1514+
PyObject *func, *retval;
1515+
1516+
func = lookup_method(self, name, &unbound);
1517+
if (func == NULL)
1518+
return NULL;
1519+
1520+
retval = call_unbound_onearg(unbound, func, self, arg);
1521+
Py_DECREF(func);
1522+
return retval;
1523+
}
1524+
1525+
static PyObject *
1526+
call_method_twoargs(PyObject *self, _Py_Identifier *name, PyObject *arg1,
1527+
PyObject *arg2)
1528+
{
1529+
int unbound;
1530+
PyObject *func, *retval;
1531+
1532+
func = lookup_method(self, name, &unbound);
1533+
if (func == NULL)
1534+
return NULL;
1535+
1536+
if (unbound) {
1537+
PyObject *args[3] = {self, arg1, arg2};
1538+
retval = _PyObject_FastCall(func, args, 3);
1539+
}
1540+
else {
1541+
PyObject *args[2] = {arg1, arg2};
1542+
retval = _PyObject_FastCall(func, args, 2);
1543+
}
1544+
Py_DECREF(func);
1545+
return retval;
1546+
}
1547+
1548+
/* Clone of call_method_onearg() that returns NotImplemented when the
1549+
lookup fails. */
15111550

15121551
static PyObject *
1513-
call_maybe(PyObject *obj, _Py_Identifier *name,
1514-
PyObject **args, Py_ssize_t nargs)
1552+
call_maybe(PyObject *self, _Py_Identifier *name, PyObject *arg)
15151553
{
15161554
int unbound;
15171555
PyObject *func, *retval;
15181556

1519-
func = lookup_maybe_method(obj, name, &unbound);
1557+
func = lookup_maybe_method(self, name, &unbound);
15201558
if (func == NULL) {
15211559
if (!PyErr_Occurred())
15221560
Py_RETURN_NOTIMPLEMENTED;
15231561
return NULL;
15241562
}
15251563

1526-
retval = call_unbound(unbound, func, obj, args, nargs);
1564+
retval = call_unbound_onearg(unbound, func, self, arg);
15271565
Py_DECREF(func);
15281566
return retval;
15291567
}
@@ -1884,13 +1922,7 @@ mro_invoke(PyTypeObject *type)
18841922

18851923
if (custom) {
18861924
_Py_IDENTIFIER(mro);
1887-
int unbound;
1888-
PyObject *mro_meth = lookup_method((PyObject *)type, &PyId_mro,
1889-
&unbound);
1890-
if (mro_meth == NULL)
1891-
return NULL;
1892-
mro_result = call_unbound_noarg(unbound, mro_meth, (PyObject *)type);
1893-
Py_DECREF(mro_meth);
1925+
mro_result = call_method_noarg((PyObject *)type, &PyId_mro);
18941926
}
18951927
else {
18961928
mro_result = mro_implementation(type);
@@ -5830,16 +5862,15 @@ static PyObject * \
58305862
FUNCNAME(PyObject *self) \
58315863
{ \
58325864
_Py_static_string(id, OPSTR); \
5833-
return call_method(self, &id, NULL, 0); \
5865+
return call_method_noarg(self, &id); \
58345866
}
58355867

58365868
#define SLOT1(FUNCNAME, OPSTR, ARG1TYPE) \
58375869
static PyObject * \
58385870
FUNCNAME(PyObject *self, ARG1TYPE arg1) \
58395871
{ \
5840-
PyObject* stack[1] = {arg1}; \
58415872
_Py_static_string(id, OPSTR); \
5842-
return call_method(self, &id, stack, 1); \
5873+
return call_method_onearg(self, &id, arg1); \
58435874
}
58445875

58455876
/* Boolean helper for SLOT1BINFULL().
@@ -5881,7 +5912,6 @@ method_is_overloaded(PyObject *left, PyObject *right, struct _Py_Identifier *nam
58815912
static PyObject * \
58825913
FUNCNAME(PyObject *self, PyObject *other) \
58835914
{ \
5884-
PyObject* stack[1]; \
58855915
_Py_static_string(op_id, OPSTR); \
58865916
_Py_static_string(rop_id, ROPSTR); \
58875917
int do_other = Py_TYPE(self) != Py_TYPE(other) && \
@@ -5893,23 +5923,20 @@ FUNCNAME(PyObject *self, PyObject *other) \
58935923
if (do_other && \
58945924
PyType_IsSubtype(Py_TYPE(other), Py_TYPE(self)) && \
58955925
method_is_overloaded(self, other, &rop_id)) { \
5896-
stack[0] = self; \
5897-
r = call_maybe(other, &rop_id, stack, 1); \
5926+
r = call_maybe(other, &rop_id, self); \
58985927
if (r != Py_NotImplemented) \
58995928
return r; \
59005929
Py_DECREF(r); \
59015930
do_other = 0; \
59025931
} \
5903-
stack[0] = other; \
5904-
r = call_maybe(self, &op_id, stack, 1); \
5932+
r = call_maybe(self, &op_id, other); \
59055933
if (r != Py_NotImplemented || \
59065934
Py_TYPE(other) == Py_TYPE(self)) \
59075935
return r; \
59085936
Py_DECREF(r); \
59095937
} \
59105938
if (do_other) { \
5911-
stack[0] = self; \
5912-
return call_maybe(other, &rop_id, stack, 1); \
5939+
return call_maybe(other, &rop_id, self); \
59135940
} \
59145941
Py_RETURN_NOTIMPLEMENTED; \
59155942
}
@@ -5920,7 +5947,7 @@ FUNCNAME(PyObject *self, PyObject *other) \
59205947
static Py_ssize_t
59215948
slot_sq_length(PyObject *self)
59225949
{
5923-
PyObject *res = call_method(self, &PyId___len__, NULL, 0);
5950+
PyObject *res = call_method_noarg(self, &PyId___len__);
59245951
Py_ssize_t len;
59255952

59265953
if (res == NULL)
@@ -5951,15 +5978,14 @@ slot_sq_item(PyObject *self, Py_ssize_t i)
59515978
PyObject *ival = PyLong_FromSsize_t(i);
59525979
if (ival == NULL)
59535980
return NULL;
5954-
retval = call_method(self, &PyId___getitem__, &ival, 1);
5981+
retval = call_method_onearg(self, &PyId___getitem__, ival);
59555982
Py_DECREF(ival);
59565983
return retval;
59575984
}
59585985

59595986
static int
59605987
slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value)
59615988
{
5962-
PyObject *stack[2];
59635989
PyObject *res;
59645990
PyObject *index_obj;
59655991

@@ -5968,13 +5994,11 @@ slot_sq_ass_item(PyObject *self, Py_ssize_t index, PyObject *value)
59685994
return -1;
59695995
}
59705996

5971-
stack[0] = index_obj;
59725997
if (value == NULL) {
5973-
res = call_method(self, &PyId___delitem__, stack, 1);
5998+
res = call_method_onearg(self, &PyId___delitem__, index_obj);
59745999
}
59756000
else {
5976-
stack[1] = value;
5977-
res = call_method(self, &PyId___setitem__, stack, 2);
6001+
res = call_method_twoargs(self, &PyId___setitem__, index_obj, value);
59786002
}
59796003
Py_DECREF(index_obj);
59806004

@@ -6001,8 +6025,7 @@ slot_sq_contains(PyObject *self, PyObject *value)
60016025
return -1;
60026026
}
60036027
if (func != NULL) {
6004-
PyObject *args[1] = {value};
6005-
res = call_unbound(unbound, func, self, args, 1);
6028+
res = call_unbound_onearg(unbound, func, self, value);
60066029
Py_DECREF(func);
60076030
if (res != NULL) {
60086031
result = PyObject_IsTrue(res);
@@ -6024,16 +6047,13 @@ SLOT1(slot_mp_subscript, "__getitem__", PyObject *)
60246047
static int
60256048
slot_mp_ass_subscript(PyObject *self, PyObject *key, PyObject *value)
60266049
{
6027-
PyObject *stack[2];
60286050
PyObject *res;
60296051

6030-
stack[0] = key;
60316052
if (value == NULL) {
6032-
res = call_method(self, &PyId___delitem__, stack, 1);
6053+
res = call_method_onearg(self, &PyId___delitem__, key);
60336054
}
60346055
else {
6035-
stack[1] = value;
6036-
res = call_method(self, &PyId___setitem__, stack, 2);
6056+
res = call_method_twoargs(self, &PyId___setitem__, key, value);
60376057
}
60386058

60396059
if (res == NULL)
@@ -6066,8 +6086,7 @@ slot_nb_power(PyObject *self, PyObject *other, PyObject *modulus)
60666086
slot_nb_power, so check before calling self.__pow__. */
60676087
if (Py_TYPE(self)->tp_as_number != NULL &&
60686088
Py_TYPE(self)->tp_as_number->nb_power == slot_nb_power) {
6069-
PyObject* stack[2] = {other, modulus};
6070-
return call_method(self, &PyId___pow__, stack, 2);
6089+
return call_method_twoargs(self, &PyId___pow__, other, modulus);
60716090
}
60726091
Py_RETURN_NOTIMPLEMENTED;
60736092
}
@@ -6134,7 +6153,7 @@ static PyObject *
61346153
slot_nb_index(PyObject *self)
61356154
{
61366155
_Py_IDENTIFIER(__index__);
6137-
return call_method(self, &PyId___index__, NULL, 0);
6156+
return call_method_noarg(self, &PyId___index__);
61386157
}
61396158

61406159

@@ -6156,9 +6175,8 @@ SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *)
61566175
static PyObject *
61576176
slot_nb_inplace_power(PyObject *self, PyObject * arg1, PyObject *arg2)
61586177
{
6159-
PyObject *stack[1] = {arg1};
61606178
_Py_IDENTIFIER(__ipow__);
6161-
return call_method(self, &PyId___ipow__, stack, 1);
6179+
return call_method_onearg(self, &PyId___ipow__, arg1);
61626180
}
61636181
SLOT1(slot_nb_inplace_lshift, "__ilshift__", PyObject *)
61646182
SLOT1(slot_nb_inplace_rshift, "__irshift__", PyObject *)
@@ -6206,6 +6224,7 @@ slot_tp_hash(PyObject *self)
62066224
}
62076225

62086226
if (func == NULL) {
6227+
PyErr_Clear();
62096228
return PyObject_HashNotImplemented(self);
62106229
}
62116230

@@ -6275,8 +6294,7 @@ slot_tp_call(PyObject *self, PyObject *args, PyObject *kwds)
62756294
static PyObject *
62766295
slot_tp_getattro(PyObject *self, PyObject *name)
62776296
{
6278-
PyObject *stack[1] = {name};
6279-
return call_method(self, &PyId___getattribute__, stack, 1);
6297+
return call_method_onearg(self, &PyId___getattribute__, name);
62806298
}
62816299

62826300
static PyObject *
@@ -6343,18 +6361,15 @@ slot_tp_getattr_hook(PyObject *self, PyObject *name)
63436361
static int
63446362
slot_tp_setattro(PyObject *self, PyObject *name, PyObject *value)
63456363
{
6346-
PyObject *stack[2];
63476364
PyObject *res;
63486365
_Py_IDENTIFIER(__delattr__);
63496366
_Py_IDENTIFIER(__setattr__);
63506367

6351-
stack[0] = name;
63526368
if (value == NULL) {
6353-
res = call_method(self, &PyId___delattr__, stack, 1);
6369+
res = call_method_onearg(self, &PyId___delattr__, name);
63546370
}
63556371
else {
6356-
stack[1] = value;
6357-
res = call_method(self, &PyId___setattr__, stack, 2);
6372+
res = call_method_twoargs(self, &PyId___setattr__, name, value);
63586373
}
63596374
if (res == NULL)
63606375
return -1;
@@ -6383,8 +6398,7 @@ slot_tp_richcompare(PyObject *self, PyObject *other, int op)
63836398
Py_RETURN_NOTIMPLEMENTED;
63846399
}
63856400

6386-
PyObject *args[1] = {other};
6387-
res = call_unbound(unbound, func, self, args, 1);
6401+
res = call_unbound_onearg(unbound, func, self, other);
63886402
Py_DECREF(func);
63896403
return res;
63906404
}
@@ -6427,7 +6441,7 @@ static PyObject *
64276441
slot_tp_iternext(PyObject *self)
64286442
{
64296443
_Py_IDENTIFIER(__next__);
6430-
return call_method(self, &PyId___next__, NULL, 0);
6444+
return call_method_noarg(self, &PyId___next__);
64316445
}
64326446

64336447
static PyObject *
@@ -6455,18 +6469,15 @@ slot_tp_descr_get(PyObject *self, PyObject *obj, PyObject *type)
64556469
static int
64566470
slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value)
64576471
{
6458-
PyObject* stack[2];
64596472
PyObject *res;
64606473
_Py_IDENTIFIER(__delete__);
64616474
_Py_IDENTIFIER(__set__);
64626475

6463-
stack[0] = target;
64646476
if (value == NULL) {
6465-
res = call_method(self, &PyId___delete__, stack, 1);
6477+
res = call_method_onearg(self, &PyId___delete__, target);
64666478
}
64676479
else {
6468-
stack[1] = value;
6469-
res = call_method(self, &PyId___set__, stack, 2);
6480+
res = call_method_twoargs(self, &PyId___set__, target, value);
64706481
}
64716482
if (res == NULL)
64726483
return -1;

0 commit comments

Comments
 (0)