Async Part 4 - What does the Hack compiler do with async functions
In the last article we looked at how the C# transforms async functions into executable code. Starting from this article we will start looking at how async functions in the Hack language are executed.
Example function
For this investigation we will be looking at a simple async function:
async function addAsync(int $a, int $b): Awaitable<int> {
$sum = $a + $b;
await HH\Asio\usleep(1000);
return $sum + 42;
}
Setting up our HHVM environment
To compile HHVM and Hack we will perform the following steps:
- Install Debian 10
- Follow the directions for building from source
- To enable disassembly, we will use the following command to configure while building:
./configure -DCMAKE_BUILD_TYPE=Debug -DMYSQL_UNIX_SOCK_ADDR=/dev/null -DENABLE_XED=ON
- To see the the HHVM bytecode and intermediate representation of our program, we will use this command to execute it:
TRACE=hhir:1,printir:2 HPHP_TRACE_FILE=/dev/stdout ./hhvm -vEval.DumpBytecode=1 ./test.hack
What Hack does with our async function
Let’s see what the HHVM bytecode generated by the compiler looks like:
Function (can_async_eager_ret) addAsync
Param: a int (HH\int)
Param: b int (HH\int)
Ret: int (HH\Awaitable<HH\int>)
maxStackCells: 6
numLocals: 3
numIterators: 0
// line 5
0: VerifyParamType L:0
2: VerifyParamType L:1
// line 2
4: CGetL L:1:1
7: CGetL2 L:0:0
10: Add
11: SetL L:2
13: PopC
// line 3
14: NullUninit
15: NullUninit
16: Int 1000
25: FCallFuncD <> 1 1 "0" 21 (46) "" "HH\\Asio\\usleep"
37: Dup
38: IsTypeC Null
40: JmpNZ 6 (46)
45: Await
46: PopC
// line 4
47: Int 42
56: CGetL2 L:2:2
59: Add
60: VerifyRetTypeC
61: RetC
We can see here that the async support is directly built into the bytecode.
At offset 45
we can see the Await
instruction.
The await operator is a first class operation in the HHVM bytecode.
Unlike C#, the Hack compiler does not transform our function into state machine.
We will have to go deeper into the HHVM compiler next time to see what’s going on.
Next time we will go deeper into HHVM intermediate representation to figure out what is going on with our async function at runtime.