-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Single-module components #435
Comments
(Sorry for the slow reply; returning from holidays) Technically, the Canonical ABI is agnostic to whether core modules import or export linear memory. E.g., today, you can write: (component
(import "./libc.wasm" (core module $Libc
(export "memory" (memory 1))
))
(core module $M
(import "libc" "memory" (memory 1))
)
(core instance $libc (instantiate $Libc))
(core instance $m (instantiate $M (with "libc" (instance $libc))))
) However, the convention of importing-vs-exporting memory does get baked into the not-yet-finalized core module build target where indeed the convention is currently that memory is exported. So is your suggestion to change the core module build target to import instead of export memory? If so, that sounds reasonable to me; I think it'd be great to encourage movement words common shared libc/allocator modules like you're suggesting. I do have a vague recollection that it might require some toolchain work to change, though. #378 is still open to discuss this, so maybe comment there? |
I had pictured it as a canonical built-in, something like this: (component
(core memory $memory (canon memory.define 1 1))
(core module $M
(import "memory-instance" "memory" (memory 1 1))
)
(core instance $m (instantiate $M (with "memory-instance" (instance (export "memory" (memory $memory))))))
) |
Historically the challenge with that idea has been that you also need a |
Today, most components in practice contain 3 core modules (not even counting the preview1-to-preview2 adapter).
The reasons this happens it that we have an import cycle. Every executable Wasm module compiled from a linear-memory language exports a linear memory, and typically imports functions which access that memory, like this:
One of the
i32
parameters towrite
is a pointer into the exported memory. This forms an implicit import cycle; the Wasm module is importing a function, the functions needs to be able to access a memory that it imports from the Wasm module.The component model disallows import cycles, however the component-model tooling knows how to automatically break cycles.
To do this, it first adds a module which defines a function table, but does not initialze it. This module has function exports to satisfy the original module's function imports, which are wrappers around
call_indirect
on an exported table:Because the function table isn't initialized here, this module doesn't import anything, so it can be instantiated first.
The other module imports that table, and imports the actual functions, and initializes the table with them:
This last module is instantiated last, and this table initialization is all it does. In all, this breaks the cycle.
It's cool that the tooling knows how to do this automatically, but it's unfortunate that this is necessary in this common situation. The
call_indirect
s add overhead, the extra modules make instantiation more complex, and all this extra code makes it difficult for people looking at components to understand how they work.One approach to fixing this that's been discussed in various places is to have special library modules that just export a linear memory and perhaps also malloc and similar functions. This may still be desirable to do for dynamic linking use cases, however that would still require two modules per component, so it's still desirable to way to avoid needing this for simple cases.
We can do this by adding support to the canonical ABI for modules that import their linear memories rather than export them. In wasm-ld, the
--import-memory
flag creates a module that imports its memory. If we use that, and add canonical-abi support for this mode, this should allow us to avoid the import cycles and the extra modules needed to break them.The text was updated successfully, but these errors were encountered: