This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: Specialize for staticmethods and classmethods
Type: Stage: patch review
Components: Versions:
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Mark.Shannon, kj
Priority: normal Keywords: patch

Created on 2022-01-26 10:01 by Mark.Shannon, last changed 2022-04-11 14:59 by admin.

Pull Requests
URL Status Linked Edit
PR 30990 closed Mark.Shannon, 2022-01-28 15:19
Messages (4)
msg411725 - (view) Author: Mark Shannon (Mark.Shannon) * (Python committer) Date: 2022-01-26 10:01
Calls of the form `x.m(args)` where either `x = X` or x = X()` and X is a class, and `m` is a classmethod or staticmethod are not currently specialized.

Typically the `x.m()` will translate to:

LOAD_FAST x
LOAD_METHOD "m"
PRECALL_METHOD 0
CALL 0

Since classmethods and staticmethods are descriptors, only the LOAD_METHOD should need specializing. The PRECALL/CALL will be able to handle the resulting values without modification.
msg411732 - (view) Author: Ken Jin (kj) * (Python committer) Date: 2022-01-26 10:40
Slightly off topic rambling:

My own toy attempts at classmethod specialization suggested that it barely sped anything up. Most of the time went to creation of the new classmethod object. I'd imagine supporting Py_TPFLAGS_METHOD_DESCRIPTOR would speed things up, but they cover such a small % of calls that Py_TPFLAGS_METHOD_DESCRIPTOR's complexity might not be worth it.

Increasing specialization percentage is always a plus though. LOAD_METHOD needs better specialization success rates.
msg411737 - (view) Author: Mark Shannon (Mark.Shannon) * (Python committer) Date: 2022-01-26 11:11
For classmethods, I expect the savings to come from not creating a bound-method and from better specialization of the following call.

classmethod case:

>>> class C:
...     @classmethod
...     def m(*args):
...          pass
... 
>>> C.m
<bound method C.m of <class '__main__.C'>>
>>> C().m
<bound method C.m of <class '__main__.C'>>

So, without specialization LOAD_METHOD "m" has the following stack effect (with `x = C()`):
x -> NULL <bound method>
C -> NULL <bound method>
With specialization:
x -> C <function>
C -> C <function>

For static methods the saving is less as there is no change in stack effect, but we do save the lookup, and we can reuse existing bytecodes.


Neither classmethod or staticmethod should have Py_TPFLAGS_METHOD_DESCRIPTOR set, as they have different semantics.
msg411758 - (view) Author: Ken Jin (kj) * (Python committer) Date: 2022-01-26 15:42
Ah woops, my bad, I mixed up the two concepts. Thanks for the thorough explanation here!
History
Date User Action Args
2022-04-11 14:59:55adminsetgithub: 90691
2022-01-28 15:19:48Mark.Shannonsetkeywords: + patch
stage: patch review
pull_requests: + pull_request29169
2022-01-26 15:42:00kjsetmessages: + msg411758
2022-01-26 11:11:01Mark.Shannonsetmessages: + msg411737
2022-01-26 10:40:22kjsetmessages: + msg411732
2022-01-26 10:01:18Mark.Shannoncreate