In Speculative Optimizations for WebAssembly using Deopts and Inlining the following statement is made:
The difference is in the code for the slow path. Without deopts, we don’t have the option of returning to baseline code, so the optimized code must handle the full, generic behavior of an indirect call, as shown in the yellow box on the left. This unfortunately impedes further optimizations and thus results in slower execution.
This implies that with deopts further optimizations can be applied, such as dead code elimination. I wonder how the Deoptimizer is able to reconstruct values that were eliminated from the inlined call, but are required for the generic call.
Consider the following example in C++ (which could then be compiled to WASM):
// inlined target
int pick(int a, int b) {
return a;
}
// call site
int(int, int)* virt_pick = pick;
int a = 0, b = 0;
for (int i = 0; i < 100; i++) {
a += rand();
b += a % 10;
}
int result = (*virt_pick)(a, b);
If pick is inlined, this could potentially be optimized to something like the following, where b is fully eliminated:
int a = 0;
for (int i = 0; i < 100; i++) {
a += rand();
}
int result = a;
But once deoptimization happens, i.e. by replacing virt_pick with a function that accesses b, b is nowhere on the stack / in registers.
How does this work? Does the Deoptimizer compute values on demand or are values still computed that might be needed for deoptimization?