-
Notifications
You must be signed in to change notification settings - Fork 825
Fuzzer: Fix up null outputs in wasm2js optimized builds #6374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In #6310 (comment), you said
nullcan be cast to0but not vice versa so we couldn't usenull. Has that changed? Or am I confused and talking about two different things?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The situation there was that
nullcan be cast to 0 but not vice versa, as you said, but the result is that we must use null. That is, if we callthen calling it from JS with
works because the JS VM will convert the second param from
nullto 0. I think that works because the wasm JS API spec does a "to number" conversion fori32, and in JS,Number(null)is 0 (for whatever historical reason). Butwould trap because
0is a number and (for whatever reason, I'm not sure) the JS spec doesn't allow that to convert to an anyref.So passing in
nullfor all params works out.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then why does passing
nullhere not work out? Does JS don't do the historic transformation here? What's the difference between this situation and that one?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Passing
nullworks out if there are casts, since the cast is what fixes it up to0as needed. But wasm2js can remove such casts in optimized builds.That never happens in non-wasm2js builds as VMs never remove such casts, so in a sense wasm2js has more flexibility than VMs there. Perhaps another solution here is for wasm2js to also not remove such casts, but it is useful for code size in release builds... that seems like the right tradeoff to me (we don't do it in debug builds of course).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought JS somehow converted it from null to 0 internally or something after reading your comment, but was that actually done by us explicitly casting with
| 0?If we replace all
nullwith0, is that OK to replace a realnullwith0? You said passing0unconditionally doesn't work because there are places we have to supplynulls like references.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The VM does it automatically and we do it manually to simulate that, yes, with
| 0. To make sure we're on the same page, in more detail, when we test in a VM, something like this happens:When we call
foo, the VM sees what types are expected. For an i32, the spec says the VM must do "to integer", so it does the JS spec operation "to integer" onnull, which turns it into a 0.On the other hand when we test in wasm2js, all we have is this:
The wasm module is implemented in JS in a way similar to that. So when we call
foowe are really just calling that JS function. JS doesn't do any casting or anything else by itself, so wasm2js emitted| 0to convert the input to a number manually. That cast mimics what the VM would do for an actual wasm module.Correct - it would be bad to replace a null with a 0. This PR doesn't do that. Maybe I misunderstood your question though?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasm2js also runs on the same VM. Then why doesn't the VM do the same thing for wasm2js and we have to simulate it for the VM?
The first line in the comment says
# replace null with 0.Also the code is
Isn't this replacing a null with a 0?
I am very much sure I'm confused about something; I am mostly just trying to understand. Sorry for making you writing a ton for a very small change.. 🥲
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One is running as wasm, and going through the JS/wasm APIs. The other is pure JavaScript. Specifically, in the first case we have
and when we call
i.exports.foothen we are calling a thing of typeWebAssembly.Function. That is an object that the spec defines as applying conversions on each parameter, according to the type of the wasm being called. In comparison, in the JS case we have (effectively)There is no
WebAssembly.Function. Instead, when we calli.exports.foowe are calling a plain JavaScript functionfoo. The JavaScript spec does not do any conversions here - in fact it can't, as it doesn't know what to convert to - there is no type declared for the parameterxof JS functionfoothere.xwill be of exactly the value that is provided, with no casting, the way JS normally works.So overall this is a weird corner case of wasm2js implementing wasm in JS: we need to copy the casts that the VM does.
Ah, yes, it is - sorry, this is indeed confusing, and I probably mixed them up before. This replaces it in the output, so they end up compared equally (when we compare outputs). But for the input, we must pass in
nullbecause of the JS casting issue (the VM will castnullto 0 for ani32param without complaint, but not vice versa, sadly).Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah OK.. What I was confused about was the substitution is done in the input vs. output of VM run. What I was talking about was the input and what you substituted was an output. It says
fix_output, but I thought this was not an output of the VM run but the output ofwasm2jsitself, which emits a JS file. So I was assuming we were modifying an input to the VM.Anyway thanks for the long conversation and sorry for the confusion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No worries, yeah, looking back the confusion was about the input vs the output, I should have made that clearer in the PR explanation...