-
-
Notifications
You must be signed in to change notification settings - Fork 4
multi value
multi-value allows riddence of smart-pointers
Multi-value is supported by modern wasm engines and makes many of the smart-pointer ideas obsolete!
Multi-value shifts the focus of smart-pointers to include a bit (flag) for optionality. This might even become a compiler only feature, making (type,value) pairs completely straight-forward.
Wasm multivalue is big for Wasp: we use it for efficiency and simplicity with much benefit.
Fortunately it is pretty much universally deployed as part of wasm runtimes, even if it's only in phase 3 of standardization.
The following snippets are only valid under the new rules introduced in the multi-value Wasm proposal:
;; A function that takes an i64
and returns ;; three i32
s.
(func (param i64) (result i32 i32 i32)
...)
;; A loop that consumes an i32
stack value ;; at the start of each iteration. loop (param i32)
... end
;; A block that produces two i32
stack values. block (result i32 i32)
... end
Functions can just leave n elements on the stack for n-tuples returns.
Functions can and do leave an extra value besides the return value: The return type smart-pointer, containing the type of the return value if all goes right, or some indication of overflow, missing value or error if things don't go as planned (or if the return type was optional).
multi-value return polymorphism
Multi-value is different to return polymorphism, but it can enable it by returning a value and it's type! so square(int) returns the tuple (return-value, type-int) and square(float) returns (return-value, type-float). We may still add external polymorphism, that is compiling square__int_as_int and square__float_as_float as two separate wasm functions. Having the option to combine them is helpful.
While the compiler could keep track of the matching types and erase them on emission, the type return is necessary in functions surfacing other components, especially 'main'. It could also be added as a custom meta section in wasm, or as part of function naming conventions like in c++. However since we already have a status channel for optionals and errors we can use the 32 bits of this return status to include the type at all times.
multi-value for riddence of smart-pointers
smart pointers can now be split int TypedValue(int32 i64) at all times, making them obsolete! In fact the pair (int32 i64) is always easy to read as in the Angle ABI int32 is always the type and i64 is always the value, now matter what.
multi-value for Interface Types multi-value for returning Small Structs More Efficiently multi-value for i32.divmod instruction of type [i32 i32] -> [i32 i32] that takes a numerator and divisor and produces both their quotient and remainder.
In core Wasm, the optional value type result of a block, loop, or if is encoded directly in the instruction:
a 0x40 byte means there is no result
a 0x7f byte means there is a single i32 result
a 0x7e byte means there is a single i64 result
etc…
With multi-value Wasm, there are not only zero or one resulting value types, there are also parameter types. Blocks can have the same set of types that functions can have. Functions already de-duplicate their types in the “Type” section of a Wasm binary and reference them via index. With multi-value, blocks do that now as well. But how does this co-exist with non-multi-value block types?
The index is encoded as a signed variable-length integer, using the LEB128 encoding. If we interpret non-multi-value blocks’ optional result value type as a signed LEB128, we get:
-64 (the smallest number that can be encoded as a single byte with signed LEB128) means there is no result
-1 means there is a single i32 result
-2 means there is a single i64 result
etc..
They’re all negative, leaving the positive numbers to be interpreted as indices into the “Type” section for multi-value blocks! A nice little encoding trick and bit of foresight from the WebAssembly standards folks.
If you pass -mmultivalue -Xclang -target-abi -Xclang experimental-mv to clang or emscripten, all by-value struct returns will become multivalue returns in WebAssembly, no matter how large the returned struct is.