Skip to content

Use WebAssembly.compileStreaming API if available #5606

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 5 commits into from
Sep 28, 2017
Merged

Conversation

dschuff
Copy link
Member

@dschuff dschuff commented Sep 27, 2017

This API is a post-MVP addition
(http://webassembly.org/docs/web/#additional-web-embedding-api) that does
streaming compilation (i.e compiles the wasm binary as it downloads), resulting
in faster instantiation in the non-cached case.

This API is a post-MVP addition
(http://webassembly.org/docs/web/#additional-web-embedding-api) that does
streaming compilation (i.e compiles the wasm binary as it downloads), resulting
in faster instantiation in the non-cached case.
@dschuff
Copy link
Member Author

dschuff commented Sep 27, 2017

Any good ideas how to test this? It requires the server to use the proper MIME type for the binary, so to test at all we'd have to have the test server do that; and to test the fallback case, we'd have to make that configurable. In any case if it's reasonable we might want to make the test server use this, since it will eventually hopefully be the most common path.

src/preamble.js Outdated
);
return {};
}
instantiateArrayBuffer(receiveInstantiatedSource);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this line be in else branch?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous if ends with a return, so no need.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer else here, since there is one more return {}; one line below, now it is duplicated in 2 places.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional nit: if we invert the conditional to put the shorter branch first, that's probably more readable whether we early-return or if-else.
Not sure if the condition is more readable as !Module['wasmBinary'] && typeof WebAssembly.instantiateStreaming === 'function' or Module['wasmBinary'] || typeof WebAssembly.instantiateStreaming !== 'function', probably the former? So, var canStream = ...; if (!canStream) { ...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little torn on that because I usually prefer positive conditions ("we can stream") and to put the "expected" case first and the unusual/exceptional case second. I went ahead and put the else in since there's only 2 cases and to deduplicate the return. How does it look now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In any case based on the discussion in #5577 we may end up with a different condition anyway...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The benefits of shorter conditionals first are more notable when composed with other if/elses, if (!foo) { bar(); return; } baz(); combines with itself much more nicely than if (foo) { baz(); } else { bar(); } does (see also, the arrow anti-pattern).
Here the function callbacks scopes are sort of serving as additional pushes and pops on the reader's mental stack. Currently the else is only ten lines away from the if so it isn't too bad, so I'm not too up in arms about it here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like that's an argument for early-return, more so than for shorter conditionals. I think in practice that does often mean short error cases go first and get early-returns, like in your linked example. But that's still "if (positive case) then error" and I want "if (positive case) then stream". I do think that if we had more than just 2 cases then the order would probably be determined by how they composed and/or how readable each condition was. With just 2 fairly-short cases it's less obvious. And also the stakes are much lower, so 🤷‍♀️

}
// Prefer streaming instantiation if available.
if (!Module['wasmBinary'] && typeof WebAssembly.instantiateStreaming === 'function') {
WebAssembly.instantiateStreaming(fetch(wasmBinaryFile, { credentials: 'same-origin' }), info)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation made this a little hard for me to read (to see where the .s go etc.). How about

WebAssembly.instantiateStreaming(
  fetch(wasmBinaryFile, { credentials: 'same-origin' }), info)
    .then(receiveInstantiatedSource)
    .catch(function(reason) {
      // We expect the most common failure cause to be a bad MIME type for the binary,
      // in which case falling back to ArrayBuffer instantiation should work.
      Module['printErr']('wasm streaming compile failed: ' + reason);
      Module['printErr']('falling back to ArrayBuffer instantiation');
      instantiateArrayBuffer(receiveInstantiatedSource);
    })
);

Also I had to add a ) so I think one might have been missing before.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, that indentation isn't right because the .then and .catch are not attached to the promise returned by fetch, they go with the return of instantiateStreaming. The fetch's promise is the first argument to instantiateStreaming. (That is also the reason why the number of parens is correct). I did make the .catch line up with the .then though, agreed that's better.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool, looks nice.

@dschuff
Copy link
Member Author

dschuff commented Sep 28, 2017

I pushed a change to use the correct MIME type in the test server. can someone remind me how to run the browser tests with wasm turned on?

@kripken
Copy link
Member

kripken commented Sep 28, 2017

browser.test_binaryen* will run the wasm-specific tests. To run the other tests in wasm mode, one way is to edit src/settings.js and set BINARYEN to 1.

@dschuff
Copy link
Member Author

dschuff commented Sep 28, 2017

OK, I verified that the test runner update does what I want (namely, set the MIME type correctly for wasm files, which makes instantiateStreaming work). So I think this patch is ready to go in. WRT use of fetch, we can continue the discussion on the other issue. This change won't break any current Electron apps because Electron's version of Chromium doesn't have instantiateStreaming yet anyway.

Copy link
Member

@kripken kripken left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm assuming the browser.test_binaryen* tests still pass.

@dschuff dschuff merged commit 24ea1a9 into incoming Sep 28, 2017
@dschuff dschuff deleted the compileStreaming branch October 9, 2017 22:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants