Commit f8362a95 authored by Andreas Haas's avatar Andreas Haas Committed by V8 LUCI CQ

[wasm] Resolve promise in separate task

With recent changes, we resolve the promise of e.g. WebAssembly.compile
with the external API, and not the V8-internal API. The external API,
however, also handles microtasks, and depending on the MicrotasksPolicy,
may also execute microtasks immediately. This means the then-handler of
WebAssembly.compile may get executed within all the scopes that were
open when the external API was called. One of the open scopes is the
CancelableTask that finishes WebAssembly compilation.

The deadlock seen in the issue arises now when {quit()} gets called in
the then-handler of WebAssembly compilation.  The reason is that
{quit()} terminates the isolate, and during isolate termination, we wait
for all running CancelableTasks to finish. This, however, means a
deadlock, because the task that terminates the isolate is waiting for
itself to finish.

R=jkummerow@chrommium.org

Bug: chromium:1338150
Change-Id: I89243daffc76a456293519e24bfaad88277bb99a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3717990Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81311}
parent 9fa64cf0
......@@ -5767,18 +5767,54 @@ ExternalPointer_t Isolate::EncodeWaiterQueueNodeAsExternalPointer(
}
#endif // V8_SANDBOXED_EXTERNAL_POINTERS
namespace {
class DefaultWasmAsyncResolvePromiseTask : public v8::Task {
public:
DefaultWasmAsyncResolvePromiseTask(v8::Isolate* isolate,
v8::Local<v8::Context> context,
v8::Local<v8::Promise::Resolver> resolver,
v8::Local<v8::Value> result,
WasmAsyncSuccess success)
: isolate_(isolate),
context_(isolate, context),
resolver_(isolate, resolver),
result_(isolate, result),
success_(success) {}
void Run() override {
v8::HandleScope scope(isolate_);
MicrotasksScope microtasks_scope(isolate_,
MicrotasksScope::kDoNotRunMicrotasks);
v8::Local<v8::Context> context = context_.Get(isolate_);
v8::Local<v8::Promise::Resolver> resolver = resolver_.Get(isolate_);
v8::Local<v8::Value> result = result_.Get(isolate_);
if (success_ == WasmAsyncSuccess::kSuccess) {
CHECK(resolver->Resolve(context, result).FromJust());
} else {
CHECK(resolver->Reject(context, result).FromJust());
}
}
private:
v8::Isolate* isolate_;
v8::Global<v8::Context> context_;
v8::Global<v8::Promise::Resolver> resolver_;
v8::Global<v8::Value> result_;
WasmAsyncSuccess success_;
};
} // namespace
void DefaultWasmAsyncResolvePromiseCallback(
v8::Isolate* isolate, v8::Local<v8::Context> context,
v8::Local<v8::Promise::Resolver> resolver,
v8::Local<v8::Value> compilation_result, WasmAsyncSuccess success) {
MicrotasksScope microtasks_scope(isolate,
MicrotasksScope::kDoNotRunMicrotasks);
if (success == WasmAsyncSuccess::kSuccess) {
CHECK(resolver->Resolve(context, compilation_result).FromJust());
} else {
CHECK(resolver->Reject(context, compilation_result).FromJust());
}
v8::Local<v8::Promise::Resolver> resolver, v8::Local<v8::Value> result,
WasmAsyncSuccess success) {
// We have to resolve the promise in a separate task which is not a cancelable
// task, to avoid a deadlock when {quit()} is called in the then-handler of
// the result promise.
V8::GetCurrentPlatform()->GetForegroundTaskRunner(isolate)->PostTask(
std::make_unique<DefaultWasmAsyncResolvePromiseTask>(
isolate, context, resolver, result, success));
}
} // namespace internal
......
// Copyright 2022 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
const builder = new WasmModuleBuilder();
builder.asyncInstantiate().then(quit);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment