Bug 238291 - [WebAssembly][Modules] Support Wasm module import from a JS Worker module
Summary: [WebAssembly][Modules] Support Wasm module import from a JS Worker module
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore JavaScript (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2022-03-23 14:39 PDT by Asumu Takikawa
Modified: 2022-04-12 21:28 PDT (History)
6 users (show)

See Also:


Attachments
Patch (16.77 KB, patch)
2022-03-23 18:16 PDT, Asumu Takikawa
no flags Details | Formatted Diff | Diff
Patch (23.85 KB, patch)
2022-03-24 15:09 PDT, Asumu Takikawa
no flags Details | Formatted Diff | Diff
Patch (26.29 KB, patch)
2022-03-29 11:27 PDT, Asumu Takikawa
no flags Details | Formatted Diff | Diff
Patch (26.45 KB, patch)
2022-03-30 16:28 PDT, Asumu Takikawa
no flags Details | Formatted Diff | Diff
Patch (29.22 KB, patch)
2022-04-11 18:09 PDT, Asumu Takikawa
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Asumu Takikawa 2022-03-23 14:39:16 PDT
A previous patch (https://bugs.webkit.org/show_bug.cgi?id=236268) added support for loading Wasm module scripts in general in WebCore, but they are not yet supported in Worker scripts.

This bug is for part of the Worker support: allowing imports of Wasm modules from inside a JS module Worker. The other aspect that's needed (not in this bug) is allowing Wasm scripts for Worker.new.
Comment 1 Asumu Takikawa 2022-03-23 18:16:42 PDT
Created attachment 455591 [details]
Patch
Comment 2 EWS Watchlist 2022-03-23 18:18:30 PDT
This patch modifies the imported WPT tests. Please ensure that any changes on the tests (not coming from a WPT import) are exported to WPT. Please see https://trac.webkit.org/wiki/WPTExportProcess
Comment 3 Yusuke Suzuki 2022-03-23 18:47:24 PDT
Comment on attachment 455591 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=455591&action=review

The patch overall looks great! Some comments.

> Source/WebCore/ChangeLog:16
> +        Instead of ignoring all other tasks, the internal timer task and
> +        tasks used for WorkerEventLoop are allowed in order to allow
> +        JS VM microtasks to be queued and run.

Could you explain a bit more detail about this?

1. What problem happens (in which code)
2. Why does it happen?
3. What is the solution to that?

> Source/WebCore/workers/WorkerEventLoop.cpp:77
> +const String WorkerEventLoop::taskMode()

`const` is not necessary as it is copying value.

> Source/WebCore/workers/WorkerRunLoop.cpp:75
> +    const String mode() const

Return `const String&`.

> Source/WebCore/workers/WorkerRunLoop.cpp:174
> +    JSC::JSRunLoopTimer::TimerNotificationCallback timerAddedTask = createSharedTask<JSC::JSRunLoopTimer::TimerNotificationType>([this, predicateMode] {

Let's pass via WTFMove(predicateMode) instead of copying.
Comment 4 Asumu Takikawa 2022-03-24 15:09:23 PDT
Created attachment 455694 [details]
Patch
Comment 5 Asumu Takikawa 2022-03-24 15:19:40 PDT
Thanks for the comments! I forgot to add a file (`WebAssemblyScriptBufferSourceProvider.h`) previously so I updated that. I'll address your other smaller comments in the next update.

> Could you explain a bit more detail about this?
>
> 1. What problem happens (in which code)
> 2. Why does it happen?
> 3. What is the solution to that?

Sure, I've updated the ChangeLog entry to have more information now and I'll explain more below.

1. The problem is that Wasm module loading gets stuck and doesn't make progress, causing tests to time out. The reason is that Wasm relies on asynchronous operations to finish module loading, and the callbacks for these are not run. This means the code ends up in `WorkerOrWorkletScriptController::loadModuleSynchronously` forever.

2. This happens because the Worker run loop, when run in a non-default mode like for module loading, never times out when looking for tasks. It also does not trigger the `timerAddedTask` that it installs as a callback for the JS VM's timer set notification. Because a non-default Worker run loop also does not run any WorkerEventLoop tasks (such as from WorkerEventLoop::scheduleToRun), microtasks from the VM for things like the Wasm module loading and promise resolution don't get run.

3. This patch solves this by allowing both the timerAddedTask (for timer set notification) and WorkerEventLoop tasks to get run by non-default run loops like for module loading.

For (3), I'm not sure if there are better solutions for this, but I'd be open to suggestions if there are. For example, maybe it's better to set a non-infinite timeout for all run loops (though I think I tried this and it wasn't sufficient). I'm also not sure if the debugging mode should perhaps be treated differently (maybe it shouldn't ever run WorkerEventLoop tasks?).
Comment 6 Asumu Takikawa 2022-03-29 11:27:57 PDT
Created attachment 456045 [details]
Patch
Comment 7 Asumu Takikawa 2022-03-29 11:31:53 PDT
I've just refined this patch to solve the problem in IMO a better way.

Instead of modifying WorkerEventLoop.cpp at all, this adds a new parameter called `useTimeout` to WorkerRunLoop's `runInMode`. It defaults to false, but when it is true, the run loop will trigger timer-based timeouts even in a non-default run mode (such as for module loading).

Then in the use of the run loop for Worker module loading, we set the parameter to true and schedule a timer so that eventually the run loop will time out and run JS VM microtasks if needed.

This should also fix the test failure that came up in the previous patch with `LayoutTests/http/wpt/resource-timing/rt-initiatorType.worker.html`.
Comment 8 Yusuke Suzuki 2022-03-29 23:31:51 PDT
(In reply to Asumu Takikawa from comment #7)
> I've just refined this patch to solve the problem in IMO a better way.
> 
> Instead of modifying WorkerEventLoop.cpp at all, this adds a new parameter
> called `useTimeout` to WorkerRunLoop's `runInMode`. It defaults to false,
> but when it is true, the run loop will trigger timer-based timeouts even in
> a non-default run mode (such as for module loading).
> 
> Then in the use of the run loop for Worker module loading, we set the
> parameter to true and schedule a timer so that eventually the run loop will
> time out and run JS VM microtasks if needed.
> 
> This should also fix the test failure that came up in the previous patch
> with `LayoutTests/http/wpt/resource-timing/rt-initiatorType.worker.html`.

Hmmm, I think probably the original approach would be simpler because it requires 20ms delay to run timer-scheduled tasks. If we are loading content from memory-cache, then I think 20ms is slow.
Comment 9 Asumu Takikawa 2022-03-30 12:21:25 PDT
> Hmmm, I think probably the original approach would be simpler because it requires 20ms delay to run timer-scheduled tasks. If we are loading content from memory-cache, then I think 20ms is slow.

That's fair. I could make the timer period shorter as well, it was set somewhat arbitrarily (e.g., a 5ms timer also passes the tests). I also wonder if the timer should be reset after the WorkerRunLoop runs, so that it has an opportunity to trigger each time (the timer period could also back off after each loop).

I could try to make the original approach work, but it seemed to cause an ordering issue in `LayoutTests/http/wpt/resource-timing/rt-initiatorType.worker.html`. Not sure why though.
Comment 10 Radar WebKit Bug Importer 2022-03-30 14:40:17 PDT
<rdar://problem/91067489>
Comment 11 Asumu Takikawa 2022-03-30 16:28:05 PDT
Created attachment 456183 [details]
Patch
Comment 12 Yusuke Suzuki 2022-04-06 03:17:28 PDT
Comment on attachment 456183 [details]
Patch

Discussed with Asumu on Slack. We should change WorkerRunLoop to drive it while loading correctly instead.
Comment 13 Asumu Takikawa 2022-04-11 18:09:51 PDT
Created attachment 457305 [details]
Patch
Comment 14 Asumu Takikawa 2022-04-11 18:12:56 PDT
I switched this patch back to the original approach where WorkerEventLoop tasks are treated specially. This time, I added a default-false bool argument for WorkerRunLoop::runMode that controls whether the WorkerEventLoop tasks should run in the mode (and set it for worker module loading run loops).

This should fix the regression the patch had earlier, since typical worker run loops will have the flag set to false.
Comment 15 Yusuke Suzuki 2022-04-12 03:23:57 PDT
Comment on attachment 457305 [details]
Patch

r=me
Comment 16 EWS 2022-04-12 21:28:26 PDT
Committed r292799 (249581@main): <https://commits.webkit.org/249581@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 457305 [details].