Skip to content
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

[spec] Normative: Permit work in parallel during instantiation #745

Merged
merged 3 commits into from
Feb 17, 2023

Conversation

littledan
Copy link
Collaborator

On JSC, some compilation work takes place the first time that a
Module is instantiated. If the module is instantiated in an
asynchronous way, the work happens off the main thread. This patch
loosens the specification of WebAssembly module instantiation
to permit this specific type of delay.

Based on skimming the code (but not running tests), I believe that
the new specification matches 3/4 of the implementations I examined.
The one which might not fit is V8, which defers reading properties
of the import object to a microtask queue item at the beginning
of WebAssembly.instantiate(Module), unlike the others, which read it
synchronously.

The previous specification didn't match any implementations, as it
specified to queue an HTML task at the beginning of the
WebAssembly.instantiate(Module) method, which no implementation
actually did to my knowledge. Punting to a queue there doesn't really
serve any purpose and was simply an error in drafting the previous
specification.

Closes #741
See also webpack/webpack#6433

@littledan littledan changed the title Normative: Permit work in parallel during instantiation [spec] Normative: Permit work in parallel during instantiation Mar 8, 2018
@littledan
Copy link
Collaborator Author

@tschneidereit
Copy link
Member

This looks good to me as a solution to the problem at hand. However, I do wonder if it wouldn't make sense to be more strict about this: I could well imagine the kinds of timing differences permitted here to cause compatibility issues at some point.

The alternative would be to specify something matching 2/4 implementations. Assuming v8 removes the additional microtask queue item before reading import object properties, that'd go up to 3/4.

@kmiller68, could you imagine living with not being compliant for a while until you've made the necessary changes? I guess we could also just make the change in this PR, have all engines be compliant for now, and tighten things later. I'm not quite sure what that'd gain, though.

@littledan
Copy link
Collaborator Author

@tschneidereit Did you see @linclark's explanation of the motivation for JSC's implementation strategy in webpack/webpack#6433 ?

@tschneidereit
Copy link
Member

@tschneidereit Did you see @linclark's explanation of the motivation for JSC's implementation strategy in webpack/webpack#6433 ?

I did see that, yes. Your and @kmiller68's comments[1][2] in #741 led me to believe that this is a slightly different case. If JSC won't change its behavior in the foreseeable future, then we should have that be reflected in the spec for sure.

[1] "@kmiller68 raised the concern that this is a change over what was previously agreed, and that JSC does make this kind of delay, though it'd be possible to remove it."
[2] "I don't think this behavior is essential and we could probably implement something different with enough effort."

@littledan
Copy link
Collaborator Author

OK, let's get more input from JSC, but this seems like part of what should go into V1 either way we decide.

@littledan
Copy link
Collaborator Author

We discussed this change in the WebAssembly WG meeting on April 19th, and my understanding is that it had consensus, to continue permitting the flexibility. Should we land this patch?

@binji
Copy link
Member

binji commented Jul 18, 2018

@littledan I don't see the notes for this discussion (also that date seems wrong, perhaps a typo?)

If this was discussed and agreed, we should merge, though it currently has conflicts.

@littledan
Copy link
Collaborator Author

The meeting date was clearly a typo. I've pushed a rebase. I can't find any meeting notes which refer to this PR. Maybe we should discuss it in the future. cc @kmiller68

@littledan
Copy link
Collaborator Author

In a later WebAssembly CG meeting, we discussed this issue further, with the suggestion to always take an event loop turn, even if it's not necessary, for consistency across platforms. In effect, this means each module instantiation has an extra setImmediate(). Presumably this would carry forward to ESM integration as well.

I'm a little worried about the performance cost here. Is anyone else? How serious would the compatibility issue be of permitting this timing difference across implementations?

@kmiller68 Could you clarify, is there any chance you could move the slow operations from the instantiate phase to the compile phase, as @tschneidereit was asking about above?

@littledan
Copy link
Collaborator Author

I've pushed a patch to make the change as described in #745 (comment) of including an event loop turn unconditionally for asynchronous instantiation. This is important to get right, partly because the semantics here also inform the WebAssembly/ESM integration semantics (where I imagine that this event loop turn will take place during module evaluation, using top-level await).

Reviews welcome. cc @Ms2ger @xtuc

document/js-api/index.bs Outdated Show resolved Hide resolved
</div>

<div algorithm>
To <dfn>instantate the core of a WebAssembly module</dfn> from a module |module| and imports |imports|, perform the following steps:
Copy link
Contributor

Choose a reason for hiding this comment

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

"core of a WebAssembly module" sounds strange to me, what about "internals of a WebAssembly module"?

@littledan
Copy link
Collaborator Author

@Ms2ger You've incrementally landed many parts of this PR. Would you be interested in rebasing it?

@Ms2ger Ms2ger force-pushed the queueing branch 2 times, most recently from 53c4677 to 83c3c26 Compare March 18, 2019 09:53
@Ms2ger
Copy link
Collaborator

Ms2ger commented Mar 20, 2019

I rebased the PR; it should now be straightforward to review. @tschneidereit, others: thoughts?

@lukewagner
Copy link
Member

As discussed in the last CG call, I landed this change in FF. (It should make it into the next Nightly.) I'll report back if we hear of any breakage, although I don't expect any.

xtuc
xtuc previously approved these changes Mar 28, 2019
@littledan
Copy link
Collaborator Author

@kmiller68, @tschneidereit and I have been discussing the semantics here. With this PR, each time a WebAssembly module is instantiated, there would be an event loop turn, in order to leave time for compilation. It sounds like this is needed for JSC the way it's implemented right now; it may be possible to rearchitect JSC for this purpose, but it's not clear yet whether that would lead to performance regressions.

I'd just like to confirm that we're comfortable with these semantics, as they're rather different from JavaScript semantics. The ESM integration proposal would carry over this per-module event loop turn.

In whatwg/html#4400 , @nyaxt , @smaug---- and @rniwa expressed some skepticism about yielding to the event loop for each JavaScript module; this patch does something similar for WebAssembly.

It may be that this is OK for WebAssembly and not for JavaScript as WebAssembly is generally a small number of big modules, whereas JavaScript may be deployed in many small modules. We may also be able to specify an event loop turn here, and later decide that it's optional or missing (however, such a two-step change could have compatibility risk).

@rossberg
Copy link
Member

WebAssembly is generally a small number of big modules, whereas JavaScript may be deployed in many small modules.

I'm not sure that we should be making assumptions of this sort.

@littledan
Copy link
Collaborator Author

I worded that a bit clumsily; I meant more like, if we expect that, then that would be one story for why not to worry about this impact/alignment with JS.

@smaug----
Copy link

smaug---- commented Mar 29, 2019

Currently the web doesn't really have explicit event loop spinning (modulo some implementation details and the somewhat unclear alert() handling in the spec). I'd rather not see us adding such. It complicates many things quite a lot. You may want to also ask blink folks why they wanted to remove showModalDialog rather quickly after finding some issue (IIRC it was causing major issues there because of nested event loop spinning, but perhaps I misremember).

If we really want event loop to spin (why?), then it needs to be clearly defined what happens if the world dies during spinning (closing window, or removing script element or modifying the contents of the script element etc.).

@littledan
Copy link
Collaborator Author

To clarify, no one here is talking about spinning the event loop. Instead, instantiating a WebAssembly module would, in this patch, have the possibility to do asynchronous work (e.g., compilation based on the imports), before queueing a task to finish the instantiation.

@lukewagner
Copy link
Member

While writing the above-mentioned patch, I realized another use case for being able to do non-trivial (off-main-thread) compilation during instantiation after the import values are known: Web IDL Bindings where, for best perf, you want to generate thunks specialized to the caller+callee.

@smaug----
Copy link

smaug---- commented Mar 29, 2019

To clarify, no one here is talking about spinning the event loop.

I see. Well, then just queue a task and continue. Of course the programming model is then a tad more error prone since the world may change before the task runs, but that happens with other APIs too.

What needs to be defined is that does the new task block page's load event firing, if the initial step is executed during pageload. And same with DOMContentLoaded.

But some concrete example somewhere would help random reader to understand the issue better.

@littledan
Copy link
Collaborator Author

@smaug---- Nothing in this PR would affect when the loaded event fires, because loading a WebAssembly module does not relate to that event. WebAssembly is loaded with APIs like instantiateStreaming, which would see one more task queued internally before running the start function; you can find examples of usage in that MDN page. With <script type=module> in the context of Wasm/ESM integration, the effects would be similar, but also not change when those events fire.

@lukewagner
Copy link
Member

As an update, the patch is about to advance to Beta. No breakage yet reported.

@smaug----
Copy link

smaug---- commented May 17, 2019

Are there wpt tests ensuring page's load event isn't affected?
I ask because in Gecko network requests before page's load event by default postpone page's load event to fire. (and if that behavior isn't wanted, request need to be marked with a certain flag.)

@littledan
Copy link
Collaborator Author

I don't know how I would write such a test, since I am not sure what scenario you are concerned about. It doesn't seem plausible to me that the JS instantiateStreaming API would block the load event; there is currently no declarative way to fetch Wasm.

@smaug----
Copy link

It has nothing to do with declarative or imperative. Just about fetching wasm.
If fetch is started right before load event for the page would otherwise fire, is the fetch finished before or after page's load event actually fires?

@rossberg
Copy link
Member

rossberg commented May 6, 2022

This PR is super-stale. Is it still relevant?

@Ms2ger
Copy link
Collaborator

Ms2ger commented May 6, 2022

I'm not sure why it never landed. It seems like SpiderMonkey and JSC might implement the change already? I can try to find time to rebase.

@rossberg
Copy link
Member

rossberg commented Aug 4, 2022

@Ms2ger, ping on this one.

JSC will have to do asynchronous compilation work during some instantiations.
To be consistent, this PR always queues a task to complete instantiation,
except through the synchronous Instance(module) API, to ensure consistency
across platforms.

This patch also cleans up the specification in various surrounding ways:
- Include notes about APIs whose use is discouraged/may be limited

Closes WebAssembly#741
See also webpack/webpack#6433
@rossberg
Copy link
Member

Any updates on this PR?

@rossberg
Copy link
Member

This PR is 5 years old and received no reaction from multiple pings over the past year. Unless there is visible activity, I will take the liberty to close it.

@Ms2ger
Copy link
Collaborator

Ms2ger commented Feb 17, 2023

As far as I can tell, this is ready to land.

@rossberg
Copy link
Member

@Ms2ger, sounds good. I'm not sure if @littledan is still available, could you take over landing this?

@Ms2ger Ms2ger merged commit 699ce94 into WebAssembly:master Feb 17, 2023
@Ms2ger Ms2ger deleted the queueing branch February 17, 2023 15:03
@tomstuart
Copy link
Contributor

tomstuart commented Feb 18, 2023

This PR was opened against master, which was the default branch at the time, but five years later the default branch is now main and it should’ve been merged into that branch instead. I’ve opened #1606 to target the correct branch.

Ms2ger added a commit that referenced this pull request Jul 27, 2023
Ms2ger added a commit that referenced this pull request Sep 26, 2023
rossberg pushed a commit that referenced this pull request Oct 13, 2023
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.

[js-api] Allow optional asynchronous steps after instantiation?
10 participants