-
Notifications
You must be signed in to change notification settings - Fork 57
Unclear how adapting imports and acyclic instantiation works #129
Comments
Great question! Indeed, pondering this question is what led me to initially file module-linking/#12. What I ultimately realized is that one can break this cycle by splitting out memory+alloc into some form of
Now, it's natural to ask: what if |
Hmm. Originally, adapter fusion was something that was done by the host as part of the import process. In that world, one would not need to specially break out malloc/free because the host has access to both the modules being linked and the adapter function being generated. |
The question here is more at the spec level: if we're specifying the way that adapter code is linked with core code in terms of Module Linking, and Module Linking requires acyclicy between instances (for good reasons, esp. once you add type imports/exports), then how do we resolve the fundamental cycle pointed out above? The engine sees all at instantiation-time of course, but that's more an implementation detail. |
The motivation for this came up when thinking about compiling interface types to normal wasm instructions (e.g. producing a module-linking-using-module without interface types at all), and when dealing with imports I wasn't quite sure what to do. I think the example in the readme will need an update one way or another because as-written it can't adapt I think? For now I settled on the table/funcref scheme where an |
@alexcrichton Would splitting out libc, as I suggested above, also work? |
It would, yeah, although the use case I was originally working with was emulating shared-nothing linking between two modules as-produced today by toolchains, none of which currently have libc split out. If we were to reorganized the two binaries, though, it would mean that there's two libc modules (one for each shared-nothing module) and we'd have to make sure all libcs come first. I was hoping that with module linking and interface types we wouldn't have to worry too too much about the structure of modules (e.g. libc and such), but rather just be able to fuse any import/export adapter as necessary (and also compiling to something without interface types if necessary to). |
FWIW, if both happened to depend on the same (or compatible) versions of libc, there could be just 1 libc module, 2 libc instances. Also, if we're talking about two shared-nothing modules A and B where A imports B, then after fusion, you'd have:
(That is, only
If we're talking about a toolchain that generates a single shared-nothing module, then yes, the toolchain would have to worry about libc insofar as it has to wire it up to its own internal import/export adapters. But if we're talking about shared-nothing-linking of separate shared-nothing modules, then I think libc details are completely encapsulated and so we don't have to worry. E.g., in a future with wasm GC, there may be no need for import adapters to call libc, but shared-nothing linking would still work the same. Does that match what you're thinking? |
Oh, and one addendum: my hope is that the core toolchain can mostly not care about interface types by:
which keeps all the interface types logic in some isolated late stage. |
Nah what you're saying all makes sense and sounds reasonable to me, I'm just trying to rationalize it with the current state of the proposal. I'm trying to figure out a way where we can transition from what we have today to interface types that doesn't involve scaling a cliff in one go, so an incremental step is to take today's monolithic modules which try to do things like import a function to print a string and adapt it (or take a string). That can't generally be done with the proposal as-written super easily because the monolithic module's malloc/free/memory can't be referenced when the import adapter is inserted. I would prefer if we could dogfood interface types without requiring everything to transition to module-linking first (since that will likely take quite some time), but I think the table-initialized-via-elem-segment is probably the way to go for that. |
Gotcha, that makes sense. |
For what it's worth, I'm been exploring how to design JS-specialized adapters for GC, and I ran into a similar problem. WebAssembly's kind of module system is known to not admit certain forms of decomposition, and consequently can't express things like |
I'm a bit late to this discussion because I don't follow the discussion on either module linking or interface types (but perhaps I should). In implementing Jawa I added a simple extension to imports called import arguments where imports can take any exportable entity as a direct argument. With relaxed section order, this allows expressing mutual dependencies between modules. I've validated that this works for expressing I explained that in a document linked in the presentation I gave, but I fear the mechanism may have been lost in the larger point I was trying to make about Wasm expression other languages, which many people seemed to regard as kooky. As such, the mechanism didn't receive as much discussion as I was expecting (none, in fact). It was hard for me to tell whether the idea was lost in the noise, or just bad. |
I was thinking about this a bit more today about how you would take an imported function that takes/returns a strings, and then connect that to a core wasm module which takes/returns pointers/lengths. The current explainer has an example which it claims shows how to do this:
I don't think this examples works, however. The
$ADAPTER
module receives a pointer/length, but it has no memory to load values from. Similarly ifadapter_func $print
wanted to return a string there's no way for$ADAPTER
to callmalloc
to allocate space for the return string.I think this may have been an accidental mistake from rebasing on top of module linking? I may also be missing something about how this is expected to work. For adapting imports though it seems like you need to first instantiate the module in question to have access to memory/malloc/etc, and then afterwards you can create adapters referencing those items. The problem though is that instantiation of the module requires the imported functions (e.g.
"print"
in this case), which is a cyclical dependency.The text was updated successfully, but these errors were encountered: