WebAssembly / js-string-builtins

JS String Builtins
Other
8 stars 6 forks source link

why not just an ambiently-available "stdlib_strings" module? #7

Closed bakkot closed 9 months ago

bakkot commented 1 year ago

Maybe there's a good reason not to do this which I'm missing, but here's an alternative design:

Alternatively, allow the "stdlib_strings" module to be specified at instantiation time, and throw only if a specific imported function is specified at instantiation time which was also available in the engine at compile time. This would allow polyfilling functions in the stdlib which aren't yet implemented in the current engine, though there would need to be some way to check which functions are available in the engine so the user could provide at instantiation time only those which actually need polyfills.

It's important that the stdlib functions contain only pure computation, to preserve the sandbox model, but the things provided here all meet that criteria.

I see there's some discussion in this thread which implies the expected way of using this is to specify a whole module. But since you'd only be able to use specific built-in modules like WebAssembly.String at compile time (lest you get a LinkError, or a best a non-postmessagable module), I don't see much advantage in letting the user specify the module at all, instead of just providing it automatically.

cc @michaelficarra

conrad-watt commented 1 year ago

If I understand correctly, the main difference is that instead of a WebAssembly.String object being user-accessible in JS-land, the availability of the namespace becomes hard-coded into the WebAssembly.compile operation?

I think some of us just recently discussed a similar idea when we bumped into each other at Wasmcon (@eqrion, @lukewagner, @ajklein - apologies if I'm getting the combination wrong) - it seems reasonable.

bakkot commented 1 year ago

Yup, exactly. That would be easier on users and also would mean you wouldn't need to worry about making things shareable.

tlively commented 1 year ago

I would like to hear more about the advantages of doing it this way, since making the import explicit rather than built into WebAssembly.compile seems like a more general and less surprising design at first blush.

bakkot commented 1 year ago

If I've understood the proposal correctly, you can't include arbitrary things at compile time, just postMessage-able things, which can never be user code. So having an explicit module would appear more general, but actually wouldn't be: it looks like the API should let you use your own functions instead of the built-in module, but you couldn't. (Or maybe you could, but the resulting module would not be postMessage-able, which is even more subtle.) So I actually think it would be less surprising to make the module built in to compile. If it's going to be magic, then it should look like magic.

The other advantages are ergonomics and simplicity. As a user it's easier if things get wired up for me, instead of me needing to specify the name and value of each stdlib module. And reifying the functions means having to deal with a bunch more cases - e.g. you need to worry about what happens if some JS code does WebAssembly.string.fromCharCode = wrap(WebAssembly.string.fromCharCode) (which which happens all the time on the web).

ajklein commented 1 year ago

Thanks, @conrad-watt; it was @guybedford who first suggested this at WasmCon, and had arguments for an approach like this that I don't see in @bakkot's response.

eqrion commented 1 year ago

The motivation in our discussions for using a builtin module of some sort for this instead of a 'compile-time import' was driven by esm-integration. See #3 and the linked source-phase imports issue for discussion of this.

I proposed a concrete change to the proposal there, but posted it on the source-phase-imports proposal instead of this one. Just reposted that there for visibility. See https://github.com/WebAssembly/js-string-builtins/issues/3#issuecomment-1720234368.

conrad-watt commented 1 year ago

using a builtin module of some sort for this instead of a 'compile-time import'

To be very pedantic, I still personally consider this solution to involve compile-time imports, except now the namespaces available for import at compile-time are hard-coded (or controlled indirectly via flags) rather than being user-controlled (at least at a surface-level).

tlively commented 1 year ago

Yes, on the Wasm side of things, this still very much looks like compile-time imports, and this is really just a change in how those imports are supplied via the JS API for compilation. This is a much more acceptable solution than what I first thought of when I heard talk of abiently available built-in modules.

eqrion commented 1 year ago

using a builtin module of some sort for this instead of a 'compile-time import'

To be very pedantic, I still personally consider this solution to involve compile-time imports, except now the namespaces available for import at compile-time are hard-coded (or controlled indirectly via flags) rather than being user-controlled (at least at a surface-level).

You're right, and that reminded me of a subtlety and tweak of the idea that I added to in #3. In effect I think it changes and reframes it enough to not be compile-time imports.

conrad-watt commented 1 year ago

To be clear, I think it's a Good Thing that builtin modules could be thought of as restricted compile-time imports! I responded in the other thread with some more thoughts on the latest iteration.

wingo commented 11 months ago

What would it look like to polyfill a stdlib_strings module? With "normal" imports, there's a straightforward story; how would you do it for ambient modules?

conrad-watt commented 11 months ago

IIUC, if the ambient module isn't provided/enabled (in whatever form it takes, flag or otherwise), the unsatisfied imports in the client module would appear during the instantiation process as "normal" imports which could be polyfilled.

This story only works so long as JS strings are represented as externref or some other core Wasm type even in the ambient module, which IIUC is currently the case. Otherwise, we'd need a story for type imports.

eqrion commented 11 months ago

Yeah, what Conrad says is accurate.

Specifically in the sketch laid out in https://github.com/WebAssembly/js-string-builtins/issues/3#issuecomment-1720234368, if you provide the flag to opt-in at compile time to having a JS string module available, then it'll be provided for you. If you want to polyfill, then remove the flag and provide it at instantiation time.

eqrion commented 9 months ago

As of #8, there is not a compile-time imports object, but instead importing from an opt-in js-string host module. I believe that resolves this.