Pack TypeIdDesc immediate more efficiently + accomodate multi-return functions
Categories
(Core :: JavaScript: WebAssembly, enhancement, P3)
Tracking
()
People
(Reporter: lth, Unassigned)
References
(Blocks 1 open bug)
Details
The TypeIdDesc (see WasmTypeDef.h for the definition and an extensive comment) is a descriptor for a function's signature. When we call_indirect the call goes to an untyped function and passes the signature the caller expects the callee has; the callee checks that. Simple signatures can be packed into an immediate and can be compared to an immediate; more complex signatures are loaded from Tls in both the caller and callee. See MacroAssembler::wasmCallIndirect() and GenerateFunctionPrologue(), respectively.
The immediate encoding handles a small number of parameters of known kinds, allocating three bits to each type. But we've talked about how the encoding could be more compact so that more signatures would fit in a uint32_t. (The "typeIndex" kind might be replaced by a "void" kind, which might get rid of the return-bit field, and the length field is probably redundant if the "void" kind could appear as a parameter.)
There's also the fact that on 64-bit systems there seems to be no good reason why we could not use a 64-bit integer, this would remove the need for loading from Tls both at the caller and at the callee in more cases. A comment in the code briefly alludes to "consistency" as the reason for using uint32_t but without supporting material this is pretty weak.
Will this matter much? At the moment, it looks like we can accomodate 7 parameters and one return value, and multi-return functions are not accomodated at all. 7 parameters is not bad; certainly a function that takes that many parameters won't speed up much by avoiding a single load. Handling multi-return seems more important, but at the moment, all but one value are returned through memory, so it won't move the needle much yet.
Also see bug 1675602 comment 4.
Reporter | ||
Comment 1•3 years ago
|
||
Another couple of points after talking to Ryan:
In the GC world, every function will take a reftype of some kind, so precisely none of the functions will have an immediate descriptor. Now it may be that in the GC world, everyone will use ref.func and call_ref, but if they use call_indirect they will be penalized unless we can come up with a better scheme.
Bit packing is sparse - can we do something denser? It's nice to have small immediates on RISC architectures, to fit into one instruction. In general small immediates are good everywhere: denser code, less memory traffic, etc. Current packing has probably been optimized for intel, where we pay for four bytes of immediate in almost every case anyway.
Comment 2•3 years ago
|
||
Here's an idea that I think would allow all types (except type imports) to have constant type ids.
- Move canonicalization of types to happen while loading a module. Currently this happens during instantiation. We can do this in general until we have type imports, at which point we would still need to defer canonicalization of types that participate in cycles with imported types.
- While compiling a signature check/call_indirect, always emit a patch-able constant pointer as the type id
- Loading of module code will patch the type id's with the pointer of the canonicalized type
- Code metadata will need to store references to the canonicalized type id's to keep them alive
- Types in cycles with imported types would need to be deferred to instantiation, and could continue to use the indirection we have now
One draw back of this approach is that we wouldn't have small immediates on RISC architectures. Might be possible to continue tagging type ID's for very common/simple function types used by C/C++/Rust.
Reporter | ||
Updated•3 years ago
|
Description
•