cfallin commented on issue #1126:
It looks like this issue's purpose was mainly to establish answers to the above questions; it looks like there is also a pending question of whether the invariants should be documented. However, it doesn't strike me that they are particularly noteworthy beyond what is already documented: the question is basically whether Cranelift follows the calling convention (restores callee-saved registers), and whether the dataflow of its output is correct (never reads an uninitialized register). These fall out of "correct compiler that follows the spec" and aren't any special additional guarantee. So I'll go ahead and close, but please feel free to ask for other clarifications as needed!
cfallin closed issue #1126:
This bug is in the context of use of Cranelift to generate wasm sandboxed libraries for use in Firefox - i.e. this is a non web embedding. Full details available here https://bugzilla.mozilla.org/show_bug.cgi?id=1562797
We are using lucet as our wasm compiler which uses Cranelift under the covers. For performance reasons, we need to optimize transitions between native code and wasm sandboxed code beyond what lucet provides out of the box. Key to this is generating efficient trampoline functions that minimize overhead.
To this end we have rewritten trampolines that make a few assumptions based on " properties derivable from the WASM spec about register and stack use of a WASM compiler". These assumptions reduces overhead when using a sandboxed version of libGraphite by several 100's of percent.
Since this is something indirectly implied from the WASM spec, I am hoping that Cranelift can guarantee these and wanted to confirm if these are OK.
There are 3 assumptions - one about stacks, and two about register use
1) Assembly functions generated by Cranelift WASM never underflows the stack
- This is guaranteed from the WASM spec due to the fact that WASM functions are proper stack machines - This would allow us to use the same stack for the application and wasm module - However, our reliance on this depends on how bug-free we think Cranelift's conversion from the WASM stack machine
2) Assembly functions generated by Cranelift never reads an uninitialized register
- This is an outcome of all function calls to WASM and within WASM (including indirect jumps) being typesafe. - This means there should never be code generated that reads from a scratch register prior to writing to it. - This also means there should never be code generate for a function that takes 2 parameters, that attempts to read a value from the register that would hold a third parameter (if it had existed) - This allows us to avoid clearing scratch and unused parameter registers during WASM function invocation.
3) Assembly functions generated by Cranelift always restore callee save registers
- Like point 2, this is an outcome of all functions being typesafe combined with the fact that WASM is a stack machine, which cannot manipulate the stack in a way that affects register spills. - This means that there should no path through the function that would result in a callee save register not being restored - This allows us to avoid explicitly restoring registers on the way out
shravanrn commented on issue #1126:
Sounds good. I had initially raised this question as we are relying on a performance optimization that made the above assumptions. If it is of interest, we have subsequently shown with formal semantics, that any spec conforming Wasm compiler must automatically meet the above restrictions, as well as the workloads and performance benefits we get. Details available here
Last updated: Nov 22 2024 at 16:03 UTC