diff --git a/filenames.gni b/filenames.gni index 6fbe0ec512699..3984417736bf5 100644 --- a/filenames.gni +++ b/filenames.gni @@ -525,6 +525,8 @@ filenames = { "shell/common/gin_helper/function_template_extensions.h", "shell/common/gin_helper/locker.cc", "shell/common/gin_helper/locker.h", + "shell/common/gin_helper/microtasks_scope.cc", + "shell/common/gin_helper/microtasks_scope.h", "shell/common/gin_helper/object_template_builder.cc", "shell/common/gin_helper/object_template_builder.h", "shell/common/gin_helper/persistent_dictionary.cc", diff --git a/shell/browser/api/electron_api_url_loader.cc b/shell/browser/api/electron_api_url_loader.cc index ac5a6cea1d408..4dd26afcf697e 100644 --- a/shell/browser/api/electron_api_url_loader.cc +++ b/shell/browser/api/electron_api_url_loader.cc @@ -28,6 +28,7 @@ #include "shell/common/gin_converters/gurl_converter.h" #include "shell/common/gin_converters/net_converter.h" #include "shell/common/gin_helper/dictionary.h" +#include "shell/common/gin_helper/microtasks_scope.h" #include "shell/common/gin_helper/object_template_builder.h" #include "shell/common/node_includes.h" @@ -135,8 +136,7 @@ class JSChunkedDataPipeGetter : public gin::Wrappable, data_producer_ = std::make_unique(std::move(pipe)); v8::HandleScope handle_scope(isolate_); - v8::MicrotasksScope script_scope(isolate_, - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate_); auto maybe_wrapper = GetWrapper(isolate_); v8::Local wrapper; if (!maybe_wrapper.ToLocal(&wrapper)) { diff --git a/shell/browser/microtasks_runner.cc b/shell/browser/microtasks_runner.cc index 5090029ce7623..94af2a9f66bc5 100644 --- a/shell/browser/microtasks_runner.cc +++ b/shell/browser/microtasks_runner.cc @@ -28,10 +28,12 @@ void MicrotasksRunner::DidProcessTask(const base::PendingTask& pending_task) { // contention for performing checkpoint between Node.js and chromium, ending // up Node.js dealying its callbacks. To fix this, now we always lets Node.js // handle the checkpoint in the browser process. - auto* node_env = electron::ElectronBrowserMainParts::Get()->node_env(); - node::InternalCallbackScope microtask_scope( - node_env->env(), v8::Local(), {0, 0}, - node::InternalCallbackScope::kAllowEmptyResource); + { + auto* node_env = electron::ElectronBrowserMainParts::Get()->node_env(); + node::InternalCallbackScope microtasks_scope( + node_env->env(), v8::Local(), {0, 0}, + node::InternalCallbackScope::kAllowEmptyResource); + } } } // namespace electron diff --git a/shell/common/api/electron_bindings.cc b/shell/common/api/electron_bindings.cc index 0b23950f91570..804f150e8e45a 100644 --- a/shell/common/api/electron_bindings.cc +++ b/shell/common/api/electron_bindings.cc @@ -25,6 +25,7 @@ #include "shell/common/gin_converters/file_path_converter.h" #include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/locker.h" +#include "shell/common/gin_helper/microtasks_scope.h" #include "shell/common/gin_helper/promise.h" #include "shell/common/heap_snapshot.h" #include "shell/common/node_includes.h" @@ -271,8 +272,7 @@ void ElectronBindings::DidReceiveMemoryDump( v8::Isolate* isolate = promise.isolate(); gin_helper::Locker locker(isolate); v8::HandleScope handle_scope(isolate); - v8::MicrotasksScope script_scope(isolate, - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate); v8::Context::Scope context_scope( v8::Local::New(isolate, context)); diff --git a/shell/common/gin_helper/callback.h b/shell/common/gin_helper/callback.h index a112f9731af57..3f716a7910031 100644 --- a/shell/common/gin_helper/callback.h +++ b/shell/common/gin_helper/callback.h @@ -13,6 +13,7 @@ #include "shell/common/gin_converters/std_converter.h" #include "shell/common/gin_helper/function_template.h" #include "shell/common/gin_helper/locker.h" +#include "shell/common/gin_helper/microtasks_scope.h" // Implements safe convertions between JS functions and base::Callback. @@ -48,8 +49,7 @@ struct V8FunctionInvoker(ArgTypes...)> { v8::EscapableHandleScope handle_scope(isolate); if (!function.IsAlive()) return v8::Null(isolate); - v8::MicrotasksScope script_scope(isolate, - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate); v8::Local holder = function.NewHandle(isolate); v8::Local context = holder->CreationContext(); v8::Context::Scope context_scope(context); @@ -73,8 +73,7 @@ struct V8FunctionInvoker { v8::HandleScope handle_scope(isolate); if (!function.IsAlive()) return; - v8::MicrotasksScope script_scope(isolate, - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate); v8::Local holder = function.NewHandle(isolate); v8::Local context = holder->CreationContext(); v8::Context::Scope context_scope(context); @@ -97,8 +96,7 @@ struct V8FunctionInvoker { ReturnType ret = ReturnType(); if (!function.IsAlive()) return ret; - v8::MicrotasksScope script_scope(isolate, - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate); v8::Local holder = function.NewHandle(isolate); v8::Local context = holder->CreationContext(); v8::Context::Scope context_scope(context); diff --git a/shell/common/gin_helper/event_emitter_caller.cc b/shell/common/gin_helper/event_emitter_caller.cc index 515f055b186e8..d725820865a57 100644 --- a/shell/common/gin_helper/event_emitter_caller.cc +++ b/shell/common/gin_helper/event_emitter_caller.cc @@ -5,6 +5,7 @@ #include "shell/common/gin_helper/event_emitter_caller.h" #include "shell/common/gin_helper/locker.h" +#include "shell/common/gin_helper/microtasks_scope.h" #include "shell/common/node_includes.h" namespace gin_helper { @@ -16,8 +17,7 @@ v8::Local CallMethodWithArgs(v8::Isolate* isolate, const char* method, ValueVector* args) { // Perform microtask checkpoint after running JavaScript. - v8::MicrotasksScope script_scope(isolate, - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate); // Use node::MakeCallback to call the callback, and it will also run pending // tasks in Node.js. v8::MaybeLocal ret = node::MakeCallback( diff --git a/shell/common/gin_helper/function_template.h b/shell/common/gin_helper/function_template.h index 1ef0979c20a79..fcf3761eb40f1 100644 --- a/shell/common/gin_helper/function_template.h +++ b/shell/common/gin_helper/function_template.h @@ -14,6 +14,7 @@ #include "shell/common/gin_helper/arguments.h" #include "shell/common/gin_helper/destroyable.h" #include "shell/common/gin_helper/error_thrower.h" +#include "shell/common/gin_helper/microtasks_scope.h" // This file is forked from gin/function_template.h with 2 differences: // 1. Support for additional types of arguments. @@ -214,8 +215,7 @@ class Invoker, ArgTypes...> template void DispatchToCallback(base::Callback callback) { - v8::MicrotasksScope script_scope(args_->isolate(), - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(args_->isolate()); args_->Return( callback.Run(std::move(ArgumentHolder::value)...)); } @@ -224,8 +224,7 @@ class Invoker, ArgTypes...> // expression to foo. As a result, we must specialize the case of Callbacks // that have the void return type. void DispatchToCallback(base::Callback callback) { - v8::MicrotasksScope script_scope(args_->isolate(), - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(args_->isolate()); callback.Run(std::move(ArgumentHolder::value)...); } diff --git a/shell/common/gin_helper/microtasks_scope.cc b/shell/common/gin_helper/microtasks_scope.cc new file mode 100644 index 0000000000000..ed3e11e2721b9 --- /dev/null +++ b/shell/common/gin_helper/microtasks_scope.cc @@ -0,0 +1,22 @@ +// Copyright (c) 2020 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "shell/common/gin_helper/microtasks_scope.h" + +#include "shell/common/gin_helper/locker.h" + +namespace gin_helper { + +MicrotasksScope::MicrotasksScope(v8::Isolate* isolate) { + if (Locker::IsBrowserProcess()) { + v8::MicrotasksScope::PerformCheckpoint(isolate); + } else { + v8_microtasks_scope_ = std::make_unique( + isolate, v8::MicrotasksScope::kRunMicrotasks); + } +} + +MicrotasksScope::~MicrotasksScope() = default; + +} // namespace gin_helper diff --git a/shell/common/gin_helper/microtasks_scope.h b/shell/common/gin_helper/microtasks_scope.h new file mode 100644 index 0000000000000..8a13284669409 --- /dev/null +++ b/shell/common/gin_helper/microtasks_scope.h @@ -0,0 +1,30 @@ +// Copyright (c) 2020 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#ifndef SHELL_COMMON_GIN_HELPER_MICROTASKS_SCOPE_H_ +#define SHELL_COMMON_GIN_HELPER_MICROTASKS_SCOPE_H_ + +#include + +#include "base/macros.h" +#include "v8/include/v8.h" + +namespace gin_helper { + +// In the browser process runs v8::MicrotasksScope::PerformCheckpoint +// In the render process creates a v8::MicrotasksScope. +class MicrotasksScope { + public: + explicit MicrotasksScope(v8::Isolate* isolate); + ~MicrotasksScope(); + + private: + std::unique_ptr v8_microtasks_scope_; + + DISALLOW_COPY_AND_ASSIGN(MicrotasksScope); +}; + +} // namespace gin_helper + +#endif // SHELL_COMMON_GIN_HELPER_MICROTASKS_SCOPE_H_ diff --git a/shell/common/gin_helper/promise.cc b/shell/common/gin_helper/promise.cc index 32737c18ab2bb..e17881ef2c4a6 100644 --- a/shell/common/gin_helper/promise.cc +++ b/shell/common/gin_helper/promise.cc @@ -26,8 +26,7 @@ PromiseBase& PromiseBase::operator=(PromiseBase&&) = default; v8::Maybe PromiseBase::Reject() { gin_helper::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); - v8::MicrotasksScope script_scope(isolate(), - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate()); v8::Context::Scope context_scope(GetContext()); return GetInner()->Reject(GetContext(), v8::Undefined(isolate())); @@ -36,8 +35,7 @@ v8::Maybe PromiseBase::Reject() { v8::Maybe PromiseBase::Reject(v8::Local except) { gin_helper::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); - v8::MicrotasksScope script_scope(isolate(), - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate()); v8::Context::Scope context_scope(GetContext()); return GetInner()->Reject(GetContext(), except); @@ -46,8 +44,7 @@ v8::Maybe PromiseBase::Reject(v8::Local except) { v8::Maybe PromiseBase::RejectWithErrorMessage(base::StringPiece message) { gin_helper::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); - v8::MicrotasksScope script_scope(isolate(), - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate()); v8::Context::Scope context_scope(GetContext()); v8::Local error = @@ -90,8 +87,7 @@ v8::Local Promise::ResolvedPromise(v8::Isolate* isolate) { v8::Maybe Promise::Resolve() { gin_helper::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); - v8::MicrotasksScope script_scope(isolate(), - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate()); v8::Context::Scope context_scope(GetContext()); return GetInner()->Resolve(GetContext(), v8::Undefined(isolate())); diff --git a/shell/common/gin_helper/promise.h b/shell/common/gin_helper/promise.h index 813eef4665b27..329756ad231dc 100644 --- a/shell/common/gin_helper/promise.h +++ b/shell/common/gin_helper/promise.h @@ -16,6 +16,7 @@ #include "content/public/browser/browser_thread.h" #include "shell/common/gin_converters/std_converter.h" #include "shell/common/gin_helper/locker.h" +#include "shell/common/gin_helper/microtasks_scope.h" namespace gin_helper { @@ -110,8 +111,7 @@ class Promise : public PromiseBase { v8::Maybe Resolve(const RT& value) { gin_helper::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); - v8::MicrotasksScope script_scope(isolate(), - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(isolate()); v8::Context::Scope context_scope(GetContext()); return GetInner()->Resolve(GetContext(), diff --git a/shell/common/node_bindings.cc b/shell/common/node_bindings.cc index b76c085dcc259..0646ffca9553b 100644 --- a/shell/common/node_bindings.cc +++ b/shell/common/node_bindings.cc @@ -29,6 +29,7 @@ #include "shell/common/gin_helper/dictionary.h" #include "shell/common/gin_helper/event_emitter_caller.h" #include "shell/common/gin_helper/locker.h" +#include "shell/common/gin_helper/microtasks_scope.h" #include "shell/common/mac/main_application_bundle.h" #include "shell/common/node_includes.h" @@ -475,8 +476,7 @@ void NodeBindings::UvRunOnce() { v8::Context::Scope context_scope(env->context()); // Perform microtask checkpoint after running JavaScript. - v8::MicrotasksScope script_scope(env->isolate(), - v8::MicrotasksScope::kRunMicrotasks); + gin_helper::MicrotasksScope microtasks_scope(env->isolate()); if (browser_env_ != BrowserEnvironment::BROWSER) TRACE_EVENT_BEGIN0("devtools.timeline", "FunctionCall");