Exported mutable globals were not a thing in MVP WebAssembly, but are now part of the spec.
Since version 0.2.66, wasm-bindgen has generated WebAssembly that uses mutable globals, but not all WebAssembly engines in the wild support the mutable globals part of the spec:
e.g. iOS 12 by virtue of shipping WebKit with OS updates (so every iPhone <= iPhone 6), Firefox ESR 60, and Node.js 10 all don't support mutable globals. They run binaries made with wasm-bindgen <= 0.2.65 without mutable globals perfectly fine.
This means that you'll never be able to run WebAssembly binaries compiled with recent and future versions of wasm-bindgen on those platforms.
My company would like to support the iPhone 6, and I know that we're not the only ones using Rust that would like to run WebAssembly binaries on engines without the mutable globals feature, and thus being forced to pin to wasm-bindgen version 0.2.65:
https://github.com/cormacrelf/citeproc-rs/commit/e0a3bddb9308c9877685e90819635f9a71b7aec4
https://github.com/cloudflare/rustwasm-worker-template/commit/fe5ce45da2415f3ac08b8cf2c6f337b109138914
https://github.com/chitalian/wasm-pack-template/commit/46f988e07495ffb6de59ad496ab15890ca5d3339
https://github.com/zakhenry/mesh-to-svg/commit/9597aecd0a67e1e3b300ac9cf81515d45555e9db
https://github.com/Emurgo/cardano-serialization-lib/commit/02432d5ae2712c26caf3113c111d749ff2f81735
https://github.com/p2panda/sesamoid/commit/43d81b3a709044986ecd7436fe57586a04d4fe15
Add a flag --disable-mutable-globals to explicitly disable emitting mutable globals. If wasm-bindgen needs to export a variable in a way that's globally writable, wasm-bindgen should emit a setter instead.
At least one other project outside the Rust ecosystem implemented a similar workaround (emitting setters instead of mutable globals) to maintain backwards compatibility with older implementations of the WebAssembly spec:
https://github.com/AssemblyScript/assemblyscript/pull/1084/commits/e03b71d0cb49c9da9ab07df993d1d7d4552044e0
The only alternative to implementing this feature, if we want to keep supporting the aforementioned WebAssembly engines, seems to be pinning wasm-bindgen's version to =0.2.65. This is really not great, since we're then stuck on that version indefinitely.
Thanks for the report! I didn't expect this to be so much of a problem in practice, but if that's the case then it should be quite easy to work around this. I think the best route would not be to not use a flag but rather instead just always inject the shim functions like AssemblyScript does. It should be relatively easy to add with walrus!
@alexcrichton That's great to hear! I'd be happy to try and implement this myself if you can give me a couple pointers as to where to start adding this walrus pass to replace mutable globals with shims :)
Ok great! The meat of what happens is here as that's the only place that needs the mutable global exported. I think this can be fixed by adding a function like __wbindgen_add_to_stack_pointer(i32) -> i32 where it'd add the provided value and return the previous or the current value (whichever is more relevant for this context).
The actual addition of the function would probably best be handled as a method on Context. That'd lazily add the new shim function to self.module. You can probably have a bool or something on Context as to whether it's been generated yet.
Actual creation of the function would use FunctionBuilder and you can see an example of that around here. It should be fine to eschew tests as well since this either works or all the tests will break :)
Most helpful comment
Ok great! The meat of what happens is here as that's the only place that needs the mutable global exported. I think this can be fixed by adding a function like
__wbindgen_add_to_stack_pointer(i32) -> i32where it'd add the provided value and return the previous or the current value (whichever is more relevant for this context).The actual addition of the function would probably best be handled as a method on
Context. That'd lazily add the new shim function toself.module. You can probably have a bool or something onContextas to whether it's been generated yet.Actual creation of the function would use
FunctionBuilderand you can see an example of that around here. It should be fine to eschew tests as well since this either works or all the tests will break :)