OPT-12 Pre-load methods for builtin types and bypass LOAD_METHOD#

Background#

CPython splits method calls into two opcode, LOAD_METHOD and CALL_METHOD. Method descriptors are handled as objects passed onto the value stack.

For LOAD_METHOD CPython will take two arguments, object and name then locate which method is to be called using the _PyObject_LoadMethod function. This function will use the slots API as well as the method-resolution-order algorithm for subclasses.

This example will load the method append() for the object n:

n = []
while len(n) < 100:
   n.append(12)

It will load the method on every iteration of the while loop even though it hasn’t changed.

Solution#

For builtin types, where the abstract type is absolute (like this example, where n has to be a list, Pyjion will create a method descriptor at compile-time and emit the address of the method descriptor instead of calling _PyObject_LoadMethod. Therefore, for every iteration, it uses the same method descriptor (which contains the address of the CFunction).

Gains#

  • Method calls on determinate methods of builtin types are faster

Edge-cases#

If a method is mocked or patched on a call in the same opcode position (e.g a loop) it will call the original method.

Further Enhancements#

The CALL_METHOD opcode could be bundled and further optimized to either call the method location directly (like PEP590 but faster).

Configuration#

This optimization is enabled at level 1 by default. See Optimizations for help on changing runtime optimization settings.