You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Calls to the type object of a native class use the slow tuple and dict calling convention #1251
Creating an instance of a native class is only fast when compiled code calls the class by name (Point(1, 2)). That is compiled to a call of the native constructor. Every other call is a call to the type object:
a call from interpreted code,
cls(...) in a class method, type(self)(...) or self.__class__(...) in compiled code,
a call through a variable that holds the class (type[Point], a callback, Any).
These go through type.__call__. CPython packs the arguments into a tuple (and a dict, if there are keyword arguments) and calls tp_new, which passes them to the wrapper function of __init__. That wrapper is a legacy one that parses the tuple and the dict with CPyArg_ParseTupleAndKeywords. Functions and other methods got vectorcall wrappers in python/mypy#9894, but __init__ was left out. There's still a TODO for it in is_fastcall_supported() (mypyc/codegen/emitmodule.py):
# TODO: Support fastcall for __init__ and __new__.returnfn.name!="__init__"andfn.name!="__new__"
Example
# point.pyclassPoint:
def__init__(self, x: int, y: int) ->None:
self.x=xself.y=ydef__add__(self, other: "Point") ->"Point":
# type(self), so that a subclass gets an instance of itself backreturntype(self)(self.x+other.x, self.y+other.y)
@classmethoddeforigin(cls) ->"Point":
returncls(0, 0)
defmake_point(x: int, y: int) ->Point:
returnPoint(x, y)
Timings from `python -m timeit -s "from point import Point, make_point; p = Point(1, 2)" "":
statement
compiled
interpreted
make_point(1, 2)
64 ns
194 ns
Point(1, 2)
103 ns
169 ns
Point(1, y=2)
155 ns
253 ns
Point(x=1, y=2)
172 ns
262 ns
p + p
111 ns
270 ns
Point.origin()
164 ns
241 ns
make_point(1, 2) creates the same object through a compiled function, which has a vectorcall wrapper
and calls the native constructor. So about 40 ns of Point(1, 2) is the calling convention, and 90 to
110 ns when there are keyword arguments. p + p and Point.origin() only run compiled code, but they
pay the same for the calls of type(self) and cls.
Activity
[mypyc] Use vectorcall for calls to the type object of a native class (…