-
Notifications
You must be signed in to change notification settings - Fork 7
Take Module-Types proposal as a Dependency? #22
Comments
Great idea! I think this opens up a new option that we haven't considered before: what if, instead of having named parameters that select which version of a nested module to use, we instead had:
So, as a strawman, a tool could generate: (module
(optional module $SIMD ...)
(optional instance $simd (instantiate $SIMD))
(module $SCALAR ...)
(instance $scalar (instantiate $SCALAR))
(module $CORE
(import "simd" (optional instance $simd ...))
(import "scalar" (instance $scalar ...))
(func $work
if (optional.test $simd)
call $simd.work
else
call $scalar.work
end
)
(instance $core (instantiate $CORE (instance $simd) (instance $scalar)))
(export $core) ;; zero-level export replaces outer modules exports with $core
) I think this simultaneously addresses two competing concerns mentioned in #20:
Even better: WASI has a strong use case for needing some form of optional imports. If the above mechanism existed, I think WASI could just use that, making WASI less magic and more like a plain library API, which is a general goal. One downside with the above strawman is that we're always compiling the fallback code. For SIMD use cases, the amount of memory/compile-time wasted is probably insignificant. For more cross-cutting features, the waste could be significant. One option I haven't thought through is to allow the presence of one optional module ( Thoughts? |
One of the main worries about conditional sections is that if the section isn't understood it causes indices to get renumbered, but I think nested modules would have a similar issue? If an optional module/instance were not understood by the engine, it may not necessarily understand how many functions/types/etc were in that module that it didn't include. Given that, how would |
Great question! In the |
Aha right! The interface from a non-simd module into a SIMD module would have to avoid using SIMD types, which means that an inner module using SIMD would always have a valid module type according to the core spec, it's just that the implementation internals wouldn't validate if an engine didn't implement SIMD. Given all that to me optional nested modules/instances sounds like a fantastic way to solve the issues that have come up with conditional sections. |
This is actually similar to the way I originally sketched conditional sections working (see WebAssembly/design#1280)! The big difference is that I originally thought we'd use the embedded module as a "feature test" module. But allowing nested modules makes this a cleaner solution, since as you say it can be the real module being verified. I'm not sure I like I have a more general question too, about using module-linking at all: Luke, in your example, you show a Is it possible to define the memory in the outer module, then import that memory in nested modules? I would think not, since the outer module hasn't been instantiated yet. But it seems like a common use case. |
Having conditional contents constrained to match a shared module type would be great. I agree with @binji that it would be better to have a static mechanism for resolving the conditions and linking the modules, though. It could be as simple as a sequence of modules, where the first one that validates is the one that is chosen. If no module in the sequence validates, the result would be a validation error. |
@binji Hah, right, I had forgotten about that; good idea :) For memory sharing: good point; I think it can be done by having a tiny utility module that only contains and exports memory. Or if the optional module is hefty, you might want a full It's possible I was overly-excited to match this with the optional imports use case. However, under the assumption that
if (optional.test $fancy-simd)
call $fancy-simd.$routine
else
do it inline
end
if (optional.test $fancy-simd-algo-1)
(call $fancy-simd-algo-1.$run (x) (y) (z))
else if (optional.test $fancy-simd-algo-2)
(call $fancy-simd-algo-2.$run (x) (y))
else
call $ya-basic
end
|
@tlively and I briefly discussed this over coffee the other day. What if we layered this proposal on top of module-types (with linking as described in WebAssembly/module-linking#3), and used nested modules here instead of conditional sections?
At a first glance, there are some nice properties here. We can fix the unstable index problem (issues #21 and #10), because the outer module will always have a fixed module type. Any helper functions/types/etc. would be local to the nested module, and the outer module could then conditionally export whichever version it prefers.
It addresses module merging issues (issue #14), since again, the outer module can choose which inner components to export/define, and can be bound by whichever constraints we like (single memory, single start section, etc.)
There are no concerns about the name section (issue #16), since the names will be attached to the whichever module defines the function/global/etc.
I'm still not quite sure how the conditional nested imports will work, though. My initial thought is that this would be a switch, where a particular import comes from 1 of N modules choosing the first predicate that is satisfied. If the predicate is never satisfied, then the module is invalid. Similarly, module definitions would be conditioned on a single predicate.
Thoughts?
The text was updated successfully, but these errors were encountered: