Skip to content
This repository has been archived by the owner on Aug 17, 2022. It is now read-only.

core vs interface type imports/exports #77

Open
fgmccabe opened this issue Oct 10, 2019 · 6 comments
Open

core vs interface type imports/exports #77

fgmccabe opened this issue Oct 10, 2019 · 6 comments

Comments

@fgmccabe
Copy link
Contributor

When crafting an adapter for an imported/exported function, it seems clumsy to have to require that any core wasm functions called in the adapter code have to be exported/imported. The adapter is written by the owner of the importing/exporting module and there they 'know' where all the functions are.
There is a case involving polyfill; but if polyfills are viewed as being implemented partly in JS and partly in wasm then they too do not need to export internal functions. (E.g., polyfill could invoke a serialization functionality within the wasm module and have the serial format interpreted/glued in JS.)

@lukewagner
Copy link
Member

What requiring core functions/memories/etc be exported from the core module buys us is:

  • spec layering: otherwise, the core spec would have to be changed to, effectively, export all definitions, and this would hurt the ecosystem's ability to, e.g., write analyses or optimizations, etc, that only understood core wasm concepts (treating only calls to imports as black boxes). In general, layering with tight interfaces between the layers (like we have now with imports/exports) is a pretty nice design ideal, I think.
  • polyfilling: a useful property for polyfilling purposes is that one could polyfill at load-time and, at this stage, be able to polyfill by only probing for and reading the contents of custom sections (in order to generate glue code), but not otherwise mutate the .wasm binary.

I think the apparent clumsiness could be addressed by sugar/conventions in the toolchain (both source code and wat).

@fgmccabe
Copy link
Contributor Author

fgmccabe commented Oct 11, 2019 via email

@lukewagner
Copy link
Member

I started to write out in more detail how we might add some desugaring rules to the @interface text format (similar to how (func (export "foo") ...) expands to both a (func ...) and (export ...) definition in core wasm text format), but I realized that, for both adapted imports and exports, both the adapted and core function signatures are meaningful b/c neither is automatically derived from the other.

Thus, the only sugar I could imagine is allowing:

(module
  (func $foo ...)
  (@interface func (export "foo")
     call $foo
  )
)

to be written and desugar into:

(module
  (func (export "foo_") ...)
  (@interface func (export "foo")
     call-export "foo_"
  )
)

The latter is definitely noisier, but it's not more lines of code, so I wonder if it's really worth it. Thoughts?

@fgmccabe
Copy link
Contributor Author

fgmccabe commented Oct 14, 2019 via email

@jgravelle-google
Copy link
Contributor

The discussion in #75 has got me thinking it might be better to use indices here and make it a semantic diff to core wasm. I'm thinking we should go as far as having this be a non-custom section.

My thoughts are: 1) I think that a runtime JS polyfill is more of a nice-to-have than a hard requirement. The more production-ready use case is going to be doing something like wasm-bindgen offline to pre-process it anyway. 2) it's potentially scary to break the encapsulation of a module by requiring a polyfill to fix up one's exports in order to maintain your boundary guarantees. If I don't want my memory exported, I'm trusting the polyfill to fix up after itself, and if I'm shipping a library I don't have control over the polyfill that gets used. 3) it makes it much easier to explain that the presence of the section has major semantic implications on the ABI, and that the section is non-ignorable by a standards-following engine.

@lukewagner
Copy link
Member

Defining specs as diffs to other specs feels a bit like using comefrom; it seems like a sign of bad layering ;)

I think the non-ignorability of the adapter section is a natural consequence of the fact that the core module's interface is super-incompatible with the adapted module interface, so the user of an adapted module really doesn't have a choice but to apply the adapter to the core module.

Also, regarding polyfills, I think the polyfill technique won't just be a short-term or only-JS thing: because it'll be non-trivial to fully integrate interface types into the N different VMs (Python, Ruby, ...) that would want to call wasm, a reasonable technique in each of these languages is to use a wasm runtime to implement core wasm, and then do some glue-code-generation or adapter-function-interpreter to connect the wasm runtime with the containing VM. Wasm runtimes only expose a module's exports, so this lines up nicely.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants