Open Bug 1599723 (wasm-abi-202x) Opened 5 years ago Updated 2 years ago

[meta] Update WebAssembly ABI for multi-value return, tail calls, optimized call_indirect

Categories

(Core :: JavaScript: WebAssembly, task, P3)

task

Tracking

()

People

(Reporter: wingo, Unassigned)

References

(Blocks 1 open bug)

Details

(Keywords: meta)

There are a number of ABI-related tasks in WebAssembly that we would like to accomplish, collectively the "WebAssembly ABI 2020" changes. Design document here:

https://docs.google.com/document/d/1oi6ROZJuE-hBb21Tgq-XcUegPktecF52gADzBJcYL34/edit#

This is a tracker bug for the wasm-abi-2020 work.

Blocks: 1599722
No longer blocks: 1573179, 1599722
Depends on: 1573179, 1599722
Priority: -- → P2
Keywords: meta
Summary: Update WebAssembly ABI for multi-value return, tail calls, optimized call_indirect → [meta] Update WebAssembly ABI for multi-value return, tail calls, optimized call_indirect

(Too broad to be p2 on its own so demoting to p3, though specific dependencies should be p2/p1 as appropriate.)

Priority: P2 → P3
Alias: wasm-abi-2020 → wasm-abi-202x

It would be worthwhile rethinking the Wasm-internal ABI in general. At the moment, we have an ABI that mostly follows the platform ABI, in that we mostly use the same return register(s) and argument registers. But we also have ambient register state, namely the Instance and the HeapReg, that needs to be preserved across intramodule calls; for intermodule calls, we perform an instance switch at the call site and then restore the instance after the return. The instance switch is expensive: it changes the instance and heap registers and also switches the realm. The ambient state is not part of the platform ABI, though we try to use nonvolatile registers for the ambient state so that C++ code will play nice with it.

In addition to that, there's an optimization in unwinding support: there are two fields in the frame for the caller's instance and the callee's instance, and these have defined values when the return address in the frame is statically tagged as being for a possibly-cross-instance call.

The ambient state and the Instance fields together reduce the memory traffic in the intramodule call case, which is expected to be by far the most common. Consider a "normal" ABI which instead passes the Instance as an argument in a call from A to B. A must save its instance value in a known slot in its frame on entry so that unwinding can work; after B returns, A must restore the instance value from that slot. B receives the instance in a register but must then load the heap pointer from the instance if the heap is needed in the function. If A has memory references, it must reload the heap pointer from the instance after the call too. (Even if the ABI has callee-saves registers it is not always safe to store the heap pointer in one, though sometimes it is.)

If that were all, it might be an affordable simplification to switch from our current ABI, which is quite complex and plays poorly with tail calls, to one that is more conventional and allows tail calls to work more easily. In that case every function will be restoring state on return, according to its own needs, and the current tail call setup that needs to specialize for the first call in a tail call chain in order to handle state restoration will not be needed. However, the realm switch issue needs to be resolved. We do not want to pay for a realm switch on every call; the realm would have to be installed properly lazily, on callouts to functions that need it. This moves the complexity elsewhere.

Somewhat orthogonal to that, I think Wasm wants to support at least two return-value registers (for the sake of Rust, Go, and some other languages), and I think it would be meaningful to use more argument registers than the platform ABI in some cases, especially if the instance moves into the regular argument registers. Right now, the Win64 ABI has only 4 GPR argument registers and 4 FPR ditto, and SIMD values are always passed on the stack (although Wasm breaks that and passes them in registers since it doesn't pass SIMD values to C++ - yet...). A more sensible ABI would align with the Linux ABI which has 6 GPRs and 8 FPRs and passes SIMD values in registers always.

Severity: normal normal → S3 S3
You need to log in before you can comment on or make changes to this bug.