OPT-9 Inline list iterators into assembly instructions#
Python objects can implement the iterator protocol.
This protocol is used in a few places:
A for loop
The iterator protocol specifies that iterator objects should be generated for a container object, like a list, tuple, or dict.
You can implement custom iterators for classes by implementing the
A Python for loop will get the iterator of the object using the
GET_ITER opcode and then keep an iterator object on the value stack for each
cycle in a loop.
The next value in the iterator object is yielded by the
FOR_ITER opcode. Most iterator objects just store an index and a pointer to the container. When
iter_next() is called
for any iterator object, the index is incremented and a pointer to the next object in the container is returned.
A new source type has been introduced,
IteratorSource, which is generated at the process stage for compilation. This is generated for
GET_ITER opcode to mark the type of iterator object that will be pushed the stack on execution of the frame. This will be determined for known types.
At the compile stage, if the abstract value kind at the top of the stack for
FOR_ITER is an
IterableValue, then the abstract kind for the
IteratorSource is inspected.
If it is an optimized type (only List for this optimization), then the IL is compiled into the function to get the next item in a listiterator, increment the index and increment the reference count
of the next item.
These inline IL codes are modelled on the
listiter_next function in CPython.
Loops for lists are faster, IF the container type can be determined as a list at compile-time
The branch logic could be improved. .NET doesn’t optimize the compiled assembly
Instead of copying
iterxx_next, a more efficient model could be used, e.g. stacking items through onto a queue and just popping them for each iteration
This optimization is enabled at level 1 by default. See Optimizations for help on changing runtime optimization settings.