Async tail-call optimization v1
Summary:
The goal of this optimization is to avoid creating new AsyncFunctionWaitHandles (AFWH) for awaits in "tail position": return await ...
If we can make this optimization, it will be a large CPU and memory win. It's tricky, though.
It's easy to identify tail awaits. Right now, I just do some simple forward analysis in HHVM, but I'll move that into HHBBC's DCE phase. It will take a bit more time to get that done, and we want to land the win earlier, so I'm putting up this version now.
The tricky part is maintaining profiling / back-tracing behavior while eliding these tail calls. One implementation of this optimization passes the AFWH to the caller instead of awaiting, but this version breaks both profiling and back-tracing completely. Dealing with profiling done through surprise checks is easy: we simply do the check before doing the optimization.
For back-tracing, we play a trick: we compress the information we need about the frame into a 2-byte ID, and we store a list of these IDs in the AFWH. When suspending, we have to do a bit more work before returning: specifically, we have to check that the incoming wait handle is an AFWH, that it we "own" it (i.e. it has few references - the correct number to check happens to be 2 - the parent and child), and that it has space in its tail frame IDs slot. AFWHPushTailFrame does this logic.
When back-tracing, to find the previous frame from an AFWH frame, we check if it has tail frames, and if so, we fall into a sub-loop using fake ActRecs, similar to inlining.
There are many follow-ups to try, which I'll get to next:
1. We can merge the "is owned AFWH" check in AFWHPushTailFrame with the state check that we do before it, saving a branch.
2. We can introduce a new AsyncTailCallWaitHandle and use that for cases where we can't merge tail frames with the existing handle.
3. We can add support for a post-await VerifyRetTypeC and handle more cases that way.
Reviewed By: jano
Differential Revision:
D20589894
fbshipit-source-id:
6d6c15857b20b1f9c0de32d2620337ca7c6b52b4