
* Remove microtasks_scope.h and microtasks_scope.cc
* Use v8::MicrotasksScope when ignoring browser checkpoint
These call always skip the browser checkpoint, so they are equivalent to using v8::MicrotasksScope directly (modulo the optional wrapper behavior).
* Remove MicrotasksScope from node_bindings.cc
This code seems contradictory: it explicitly specifies "do not run microtasks" yet runs a microtask checkpoint in the browser process.
Looking at its history, it [was introduced][1] with the intention to not run microtasks, but a [subtle C++ language behavior][2] caused it to do the opposite later in the same roll. Since the original intention was to not run microtasks, and since that is also the simplest explanation, we can assume `ignore_browser_checkpoint` should be true and migrate this to `v8::MicrotasksScope` as it is equivalent (modulo the optional wrapper behavior).
[1]: a4ea80dd47 (diff-efe58cf03c97028f37f801db044d396a5f428686da6595d2c692f1c052bbd09c)
[2]: https://github.com/electron/electron/pull/43185
* Migrate gin_helper/promise.h and gin_helper/promise.cc to v8::MicrotasksScope
Restores the [original][1] behavior of running the microtask checkpoint at destruction, but preserves the behavior of running microtasks in the browser process. This had last changed in the migration to gin_helper::MicroTasks.
[1]: https://github.com/electron/electron/pull/16401
127 lines
3.9 KiB
C++
127 lines
3.9 KiB
C++
// Copyright (c) 2018 GitHub, Inc.
|
|
// Use of this source code is governed by the MIT license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include <string>
|
|
#include <string_view>
|
|
|
|
#include "content/public/browser/browser_task_traits.h"
|
|
#include "content/public/browser/browser_thread.h"
|
|
#include "shell/common/gin_helper/promise.h"
|
|
#include "shell/common/process_util.h"
|
|
#include "v8/include/v8-context.h"
|
|
|
|
namespace gin_helper {
|
|
|
|
PromiseBase::SettleScope::SettleScope(const PromiseBase& base)
|
|
: handle_scope_{base.isolate()},
|
|
context_{base.GetContext()},
|
|
microtasks_scope_(context_, v8::MicrotasksScope::kRunMicrotasks),
|
|
context_scope_{context_} {}
|
|
|
|
PromiseBase::SettleScope::~SettleScope() {
|
|
if (electron::IsBrowserProcess()) {
|
|
context_->GetMicrotaskQueue()->PerformCheckpoint(context_->GetIsolate());
|
|
}
|
|
}
|
|
|
|
PromiseBase::PromiseBase(v8::Isolate* isolate)
|
|
: PromiseBase(isolate,
|
|
v8::Promise::Resolver::New(isolate->GetCurrentContext())
|
|
.ToLocalChecked()) {}
|
|
|
|
PromiseBase::PromiseBase(v8::Isolate* isolate,
|
|
v8::Local<v8::Promise::Resolver> handle)
|
|
: isolate_(isolate),
|
|
context_(isolate, isolate->GetCurrentContext()),
|
|
resolver_(isolate, handle) {}
|
|
|
|
PromiseBase::PromiseBase() : isolate_(nullptr) {}
|
|
|
|
PromiseBase::PromiseBase(PromiseBase&&) = default;
|
|
|
|
PromiseBase::~PromiseBase() = default;
|
|
|
|
PromiseBase& PromiseBase::operator=(PromiseBase&&) = default;
|
|
|
|
// static
|
|
scoped_refptr<base::TaskRunner> PromiseBase::GetTaskRunner() {
|
|
if (electron::IsBrowserProcess() &&
|
|
!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
|
|
return content::GetUIThreadTaskRunner({});
|
|
}
|
|
return {};
|
|
}
|
|
|
|
v8::Maybe<bool> PromiseBase::Reject(v8::Local<v8::Value> except) {
|
|
SettleScope settle_scope{*this};
|
|
return GetInner()->Reject(settle_scope.context_, except);
|
|
}
|
|
|
|
v8::Maybe<bool> PromiseBase::Reject() {
|
|
SettleScope settle_scope{*this};
|
|
return GetInner()->Reject(settle_scope.context_, v8::Undefined(isolate()));
|
|
}
|
|
|
|
v8::Maybe<bool> PromiseBase::RejectWithErrorMessage(std::string_view errmsg) {
|
|
SettleScope settle_scope{*this};
|
|
return GetInner()->Reject(
|
|
settle_scope.context_,
|
|
v8::Exception::Error(gin::StringToV8(isolate(), errmsg)));
|
|
}
|
|
|
|
v8::Local<v8::Context> PromiseBase::GetContext() const {
|
|
return v8::Local<v8::Context>::New(isolate_, context_);
|
|
}
|
|
|
|
v8::Local<v8::Promise> PromiseBase::GetHandle() const {
|
|
return GetInner()->GetPromise();
|
|
}
|
|
|
|
v8::Local<v8::Promise::Resolver> PromiseBase::GetInner() const {
|
|
return resolver_.Get(isolate());
|
|
}
|
|
|
|
// static
|
|
void PromiseBase::RejectPromise(PromiseBase&& promise,
|
|
std::string_view errmsg) {
|
|
if (auto task_runner = GetTaskRunner()) {
|
|
task_runner->PostTask(
|
|
FROM_HERE, base::BindOnce(
|
|
// Note that this callback can not take std::string_view,
|
|
// as StringPiece only references string internally and
|
|
// will blow when a temporary string is passed.
|
|
[](PromiseBase&& promise, std::string str) {
|
|
promise.RejectWithErrorMessage(str);
|
|
},
|
|
std::move(promise), std::string{errmsg}));
|
|
} else {
|
|
promise.RejectWithErrorMessage(errmsg);
|
|
}
|
|
}
|
|
|
|
// static
|
|
void Promise<void>::ResolvePromise(Promise<void> promise) {
|
|
if (auto task_runner = GetTaskRunner()) {
|
|
task_runner->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce([](Promise<void> promise) { promise.Resolve(); },
|
|
std::move(promise)));
|
|
} else {
|
|
promise.Resolve();
|
|
}
|
|
}
|
|
|
|
// static
|
|
v8::Local<v8::Promise> Promise<void>::ResolvedPromise(v8::Isolate* isolate) {
|
|
Promise<void> resolved(isolate);
|
|
resolved.Resolve();
|
|
return resolved.GetHandle();
|
|
}
|
|
|
|
v8::Maybe<bool> Promise<void>::Resolve() {
|
|
SettleScope settle_scope{*this};
|
|
return GetInner()->Resolve(settle_scope.context_, v8::Undefined(isolate()));
|
|
}
|
|
|
|
} // namespace gin_helper
|