Potential web compatibility issue with exports of globals
From Globals.md, in the WebAssembly.Instance constructor
- if e is a global instance g with global_type gt:
- Return a new WebAssembly.Global with [[Global]] set to g and [[GlobalType]] set to gt.
Does this apply even for existing, immutable globals? It seems like if a website is using the global values with WebAssembly now, this would change how they would have to use it, resulting in a potential compatibility issue. Or am I understanding this wrong?
One workaround would be to expose constants as their value, and expose mutable globals as a WebAssembly.Global. This could still allow constant WebAssembly.Global objects to be constructed and used as imports.
Yeah, there is a potential compatibility risk here, but I think it's low, and decided having uniformity is nicer. I believe we came to the same conclusion at a CG meeting as well, let me see if I can find it.
edit: can't seem to find it. Perhaps someone else knows where this was discussed (or am I imagining it?)
Is the expectation then that no one is using global exports? Maybe they could just be omitted for now so that no one starts depending on them, until browsers are ready to ship threads.
The hope was that the existing usage would be covered by the @@toPrimitive hook, and most users won't care that they're getting a different object under the hood. I also doubt that many people are using global exports. But admittedly, we haven't looked into this.
I know this is sort of ugly, but if we want uniformity of API on the one side and compatibility on the other, could we solve this with a flag on the export s.t. if the flag is set we get a WebAssembly.Global instance and if the flag is not set we get the value? For mutable globals it could(*) be an error if the flag is not set.
The flag might actually have to show up as a new external_kind that can only be used with a Global definition (not with global imports). Kind=3 would be renamed as 'Global value', Kind=4 might be 'Global cell'.
For that matter, could/should this distinction be made to apply to imports in some way? If the flag is not set, the import has to be a value, as before; if it is set, the import has to be a cell.
(*) Logically that's not necessary, you'd just get a snapshot of the value of the global, as you in a sense do for immutable globals.
A flag in the wasm binary format?
Yes, in the binary format. It's possible something would then also be needed in the textual format to express exporting immutable globals as WebAsssembly.Global, say, (global (export "g" box) i32 (i32.const 37)).
Since this is solely a JS side matter, the only suitable place to add such information would be the JS host binding section. But is it really necessary?
I don't see the need for something in the binary format. If web compatibility is a concern that isn't considered to be handled by @@toPrimitive, what would be the disadvantage of exporting immutable globals as they are (bare Numbers) and exporting mutable globals as WebAssembly.Global objects?
@rossberg I understand the layering issue that it's better to keep it in the host binding section, but to give the uniformity that @lars-t-hansen is looking for, how would you handle it purely there? A specialized custom section for this purpose?
to give the uniformity that @lars-t-hansen is looking for,
Personally I don't care a whit about uniformity, I merely wrote down a thought in response to the preceding discussion, which had cast doubt on whether uniformity (as designed in the proposal) was compatible with the web.
Yeah, I was pushing for uniformity mostly because I didn't think it would be an issue. But if it is (or if we think it may be, and aren't sure) then I think it's OK to just do what you said @littledan: bare numbers for immutable globals and WebAssembly.Global for mutable globals.
Personally, I value the uniformity and think the @@toPrimitive solution is a good idea and the compatibility risk is pretty low at this early stage. I think we should try to do it, as in ship the "breaking" change ASAP, see if it breaks anything in practice and go the non-uniform backwards-compatible route otherwise.
If we want to rip the bandaid off as fast as possible, should we make the change to WebAssembly.Global objects now, even before threads are shipped?
That's a good idea. It might be worth bringing up at the CG how this would go through the phases, considering it's a JS facing change only.
We discussed this at the Nov 28 CG. Some notes:
- It's useful to have WebAssembly.Global for immutable globals, since we may not be able to express the type in JS but we still may want to wire up between two wasm instances (for i64 or maybe some future type).
- You'll have to specify at creation whether a WebAssembly.Global is mutable
- An immutable global cannot be imported as mutable, nor a mutable global imported as immutable
As for the breaking change, @lukewagner will look into testing this with Firefox nightly
I've implemented enough of the breaking change in Firefox to experiment with this. Specifically: there is a WebAssembly.Global type that can represent globals (only immutable, for now); the instance's export object contains instances of WebAssembly.Global instead of the exported globals' values; and the import descriptor can hold either raw values or WebAssembly.Global objects. With this change, a small number of test cases had to be updated, but both Tanks and Zen Garden run as they should.
So now I guess we need to figure out whether/when we can ship this on the Nightly channel to see if anyone complains about altered functionality...
Patches on https://bugzil.la/1412238, work in progress.
Landed. See forked bug for more.