Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: Adds support for JIT generators with 3.12. Note coroutines and async-generators are NOT covered by this diff but should come soon. Unlike in 3.10, this implementation does not modify `genobject.c` or anything else in the upstream runtime, making it suitable for pip-install. We achieve this by making a new type for JIT generators (implemented in `generators_rt.cpp`) rather than modifying the existing type's features directly. In theory our new type could be implemented however we want, provided it satisfies the generator API. In practice we must keep the same object data layout and content as the original type to allow for deopt. While this does constrain us, it's also handy as most of the implementation (getters, methods, etc.) are just copied directly from the original generator object. Where we can't copy something because it needs to be different we still have the option to deopt in places and defer back to the original implementation on slow-paths like errors, exceptions, etc. During development I started by converting our 3.10 implementation to also use a custom type. However, I've discarded this and instead this change only adds this to 3.12. While there are advantages to a unified implementation for 3.10 + 3.12, I think the benefits are outweighed by the 3.10 implementation being quite different and considerably more complicated due the need to support shadow frames. The differences means we're often not getting the benefit of verifying what we're developing for 3.12 on 3.10 and it considerably bloats the implementation and makes it harder to follow. Another minor but irritating difference is in 3.12 there is only one object layout for generators, coroutines, and async-generators. This actually makes life easier in 3.12 but we'd have to do something different to work with the old 3.10 model too. Most of the existing JIT infrastructure for implementing a generator function is reused with some minor differences. The biggest difference is we immediately allocate the generator object and link it into the Python stack at the start of the function, rather than deferring construction to "initial yield". This new implementation is probably more efficient as it means we can begin using register spill space in the generator object immediately rather than initially using using the stack and then copying the content over later. Another smaller difference is 3.12 provides some more fine-grained opcodes for some generator implementation, but these mostly map to existing concepts so are not hard to implement. Reviewed By: DinoV Differential Revision: D66567769 fbshipit-source-id: 8b146489c44e7b3b923f67bdc578a36d797f8367
- Loading branch information