From 8ebd1cef7800f42736efe0f2e707a1dc4754934a Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 8 Sep 2026 11:26:24 +0200 Subject: [PATCH 1/3] Revert "deps: V8: backport b36cf9f6ccd2" This reverts commit ccd648eb0cf0bbf1fee0ffa9a6fc91f9101ce508. --- deps/v8/BUILD.bazel | 6 ---- deps/v8/BUILD.gn | 11 ------ deps/v8/src/common/assert-scope.h | 2 +- deps/v8/src/execution/isolate.cc | 7 ---- deps/v8/src/inspector/v8-debugger.cc | 1 - deps/v8/src/inspector/v8-inspector-impl.cc | 1 - .../inspector/v8-inspector-session-impl.cc | 2 -- deps/v8/src/inspector/v8-regex.cc | 2 -- deps/v8/test/cctest/test-api.cc | 20 ----------- deps/v8/test/cctest/test-regexp.cc | 8 +---- .../debugger/debug/futex-reentrant-wait.js | 35 ------------------- 11 files changed, 2 insertions(+), 93 deletions(-) delete mode 100644 deps/v8/test/debugger/debug/futex-reentrant-wait.js diff --git a/deps/v8/BUILD.bazel b/deps/v8/BUILD.bazel index 53c06e3ceccf..f28fea4e8aa1 100644 --- a/deps/v8/BUILD.bazel +++ b/deps/v8/BUILD.bazel @@ -148,11 +148,6 @@ v8_flag(name = "v8_enable_trace_maps") v8_flag(name = "v8_enable_v8_checks") -v8_flag( - name = "v8_disallow_js_in_api_interrupts_is_checked", - default = True, -) - v8_flag(name = "v8_enable_verify_csa") v8_flag(name = "v8_enable_verify_heap") @@ -501,7 +496,6 @@ v8_config( "v8_android_log_stdout": "V8_ANDROID_LOG_STDOUT", "v8_code_comments": "V8_CODE_COMMENTS", "v8_deprecation_warnings": "V8_DEPRECATION_WARNINGS", - "v8_disallow_js_in_api_interrupts_is_checked": "V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED", "v8_imminent_deprecation_warnings": "V8_IMMINENT_DEPRECATION_WARNINGS", "v8_enable_debug_code": "V8_ENABLE_DEBUG_CODE", "v8_enable_disassembler": "ENABLE_DISASSEMBLER", diff --git a/deps/v8/BUILD.gn b/deps/v8/BUILD.gn index ea335df90341..e81430fbc393 100644 --- a/deps/v8/BUILD.gn +++ b/deps/v8/BUILD.gn @@ -59,10 +59,6 @@ declare_args() { # Enable compiler warnings when using V8_DEPRECATED apis. v8_deprecation_warnings = true - # Check that executing JavaScript inside API interrupt callbacks is - # disallowed. - v8_disallow_js_in_api_interrupts_is_checked = true - # Enable compiler warnings when using V8_DEPRECATE_SOON apis. v8_imminent_deprecation_warnings = true @@ -1003,7 +999,6 @@ external_v8_defines = [ "V8_COMPRESS_ZONES", "V8_ENABLE_SANDBOX", "V8_DEPRECATION_WARNINGS", - "V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED", "V8_IMMINENT_DEPRECATION_WARNINGS", "V8_USE_PERFETTO", "V8_USE_PERFETTO_JSON_EXPORT", @@ -1052,10 +1047,6 @@ if (v8_enable_sandbox) { if (v8_deprecation_warnings) { enabled_external_v8_defines += [ "V8_DEPRECATION_WARNINGS" ] } -if (v8_disallow_js_in_api_interrupts_is_checked) { - enabled_external_v8_defines += - [ "V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED" ] -} if (v8_imminent_deprecation_warnings) { enabled_external_v8_defines += [ "V8_IMMINENT_DEPRECATION_WARNINGS" ] } @@ -3102,8 +3093,6 @@ generated_file("v8_generate_features_json") { output_conversion = "json" contents = { v8_deprecation_warnings = v8_deprecation_warnings - v8_disallow_js_in_api_interrupts_is_checked = - v8_disallow_js_in_api_interrupts_is_checked v8_enable_31bit_smis_on_64bit_arch = v8_enable_31bit_smis_on_64bit_arch v8_enable_direct_handle = v8_enable_direct_handle v8_enable_extensible_ro_snapshot = v8_enable_extensible_ro_snapshot diff --git a/deps/v8/src/common/assert-scope.h b/deps/v8/src/common/assert-scope.h index 494d330b3332..cf82be0bc8ee 100644 --- a/deps/v8/src/common/assert-scope.h +++ b/deps/v8/src/common/assert-scope.h @@ -110,7 +110,7 @@ class V8_NODISCARD PerThreadAssertScope ScopeType& operator=(const ScopeType&) = delete; \ V8_EXPORT_PRIVATE ~ScopeType(); \ \ - V8_EXPORT_PRIVATE static bool IsAllowed(Isolate* isolate); \ + static bool IsAllowed(Isolate* isolate); \ \ V8_EXPORT_PRIVATE static void Open(Isolate* isolate, \ bool* was_execution_allowed); \ diff --git a/deps/v8/src/execution/isolate.cc b/deps/v8/src/execution/isolate.cc index 37c72639cd7f..74762de5a9aa 100644 --- a/deps/v8/src/execution/isolate.cc +++ b/deps/v8/src/execution/isolate.cc @@ -2357,13 +2357,6 @@ void Isolate::InvokeApiInterruptCallbacks() { } VMState state(this); HandleScope handle_scope(this); - // API interrupt callbacks are forbidden from executing JavaScript on the - // interrupted Isolate (see v8::Isolate::RequestInterrupt contract in - // v8-isolate.h: "Registered |callback| must not reenter interrupted - // Isolate."). -#ifdef V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED - DisallowJavascriptExecution no_js(this); -#endif // V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED entry.first(reinterpret_cast(this), entry.second); } } diff --git a/deps/v8/src/inspector/v8-debugger.cc b/deps/v8/src/inspector/v8-debugger.cc index 747abefcedd5..69fb293610bc 100644 --- a/deps/v8/src/inspector/v8-debugger.cc +++ b/deps/v8/src/inspector/v8-debugger.cc @@ -532,7 +532,6 @@ void V8Debugger::handleProgramBreak( } }); { - v8::Isolate::AllowJavascriptExecutionScope allow_script(m_isolate); v8::Context::Scope scope(pausedContext); m_inspector->forEachSession( diff --git a/deps/v8/src/inspector/v8-inspector-impl.cc b/deps/v8/src/inspector/v8-inspector-impl.cc index f085f7f72ec7..a4610e0d9b33 100644 --- a/deps/v8/src/inspector/v8-inspector-impl.cc +++ b/deps/v8/src/inspector/v8-inspector-impl.cc @@ -96,7 +96,6 @@ int V8InspectorImpl::resolveUniqueContextId( v8::MaybeLocal V8InspectorImpl::compileAndRunInternalScript( v8::Local context, v8::Local source) { - v8::Isolate::AllowJavascriptExecutionScope allow_script(m_isolate); v8::Local unboundScript; if (!v8::debug::CompileInspectorScript(m_isolate, source) .ToLocal(&unboundScript)) diff --git a/deps/v8/src/inspector/v8-inspector-session-impl.cc b/deps/v8/src/inspector/v8-inspector-session-impl.cc index 38d8dd93ea41..95ae57032b32 100644 --- a/deps/v8/src/inspector/v8-inspector-session-impl.cc +++ b/deps/v8/src/inspector/v8-inspector-session-impl.cc @@ -355,8 +355,6 @@ void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) { } void V8InspectorSessionImpl::dispatchProtocolMessage(StringView message) { - v8::Isolate::AllowJavascriptExecutionScope allow_script( - m_inspector->isolate()); KeepSessionAliveScope keepAlive(*this); using v8_crdtp::span; diff --git a/deps/v8/src/inspector/v8-regex.cc b/deps/v8/src/inspector/v8-regex.cc index 09c308f84d38..4adf347843ff 100644 --- a/deps/v8/src/inspector/v8-regex.cc +++ b/deps/v8/src/inspector/v8-regex.cc @@ -38,7 +38,6 @@ V8Regex::V8Regex(V8InspectorImpl* inspector, const String16& pattern, v8::Local regex; // Protect against reentrant debugger calls via interrupts. v8::debug::PostponeInterruptsScope no_interrupts(m_inspector->isolate()); - v8::Isolate::AllowJavascriptExecutionScope allow_js(m_inspector->isolate()); if (v8::RegExp::New(context, toV8String(isolate, pattern), static_cast(flags)) .ToLocal(®ex)) @@ -70,7 +69,6 @@ int V8Regex::match(const String16& string, int startFrom, v8::MicrotasksScope::kDoNotRunMicrotasks); // Protect against reentrant debugger calls via interrupts. v8::debug::PostponeInterruptsScope no_interrupts(m_inspector->isolate()); - v8::Isolate::AllowJavascriptExecutionScope allow_js(m_inspector->isolate()); v8::TryCatch tryCatch(isolate); v8::Local regex = m_regex.Get(isolate); diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index 9b5fdd3cfd96..ba7e079f411c 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -22306,26 +22306,6 @@ TEST(RequestInterruptSmallScripts) { CHECK(interrupt_was_called); } -#ifdef V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED -static bool interrupt_check_no_js = false; -void DisallowJsInterruptCallback(v8::Isolate* isolate, void* data) { - CHECK(!i::AllowJavascriptExecution::IsAllowed( - reinterpret_cast(isolate))); - interrupt_check_no_js = true; -} - -TEST(RequestInterruptDisallowsJavascript) { - LocalContext env; - v8::Isolate* isolate = CcTest::isolate(); - v8::HandleScope scope(isolate); - - interrupt_check_no_js = false; - isolate->RequestInterrupt(&DisallowJsInterruptCallback, nullptr); - CompileRun("(function(x){return x;})(1);"); - CHECK(interrupt_check_no_js); -} -#endif // V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED - static v8::Global function_new_expected_env_global; static void FunctionNewCallback(const v8::FunctionCallbackInfo& info) { v8::Isolate* isolate = info.GetIsolate(); diff --git a/deps/v8/test/cctest/test-regexp.cc b/deps/v8/test/cctest/test-regexp.cc index 08be47b221a8..946695833c64 100644 --- a/deps/v8/test/cctest/test-regexp.cc +++ b/deps/v8/test/cctest/test-regexp.cc @@ -124,13 +124,7 @@ class InterruptTest { CHECK(string->ContainsOnlyOneByte()); // Internalize the subject by using it as a computed property name in an // object. - { - // This test is technically wrong for running JS in a C++ interrupt. - // However we know that the interuptee here is the regexp engine, which - // does not care. - Isolate::AllowJavascriptExecutionScope allow_script(isolate); - CompileRun("o = { [subject_string]: 'foo' }"); - } + CompileRun("o = { [subject_string]: 'foo' }"); CHECK(string->IsOneByte()); } diff --git a/deps/v8/test/debugger/debug/futex-reentrant-wait.js b/deps/v8/test/debugger/debug/futex-reentrant-wait.js deleted file mode 100644 index fc82beac534e..000000000000 --- a/deps/v8/test/debugger/debug/futex-reentrant-wait.js +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2026 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. - -// Flags: --allow-natives-syntax - -var Debug = debug.Debug; -var exception = null; - -Debug.setListener(function (event, exec_state, event_data, data) { - if (event == Debug.DebugEvent.Break) { - try { - var sab2 = new SharedArrayBuffer(4); - var i32a2 = new Int32Array(sab2); - Atomics.wait(i32a2, 0, 0, 10); - } catch (e) { - exception = e; - } - } -}); - -let sab = new SharedArrayBuffer(4); -let i32a = new Int32Array(sab); - -let timeout = { - valueOf: function() { - %ScheduleBreak(); - return 10; - } -}; - -Atomics.wait(i32a, 0, 0, timeout); - -assertNotNull(exception); -assertTrue(exception.message.includes("cannot be called in this context")); From 9d030b69fc6876308f6cc1e8a24946e94986c972 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 8 Sep 2026 11:26:26 +0200 Subject: [PATCH 2/3] Revert "deps: enable V8 API interrupt JS check" This reverts commit 49e26084925d3e177000cc1bcb74b76f8b108f7b. --- common.gypi | 5 ----- tools/v8_gypfiles/features.gypi | 6 ------ 2 files changed, 11 deletions(-) diff --git a/common.gypi b/common.gypi index ce602beccf66..e6a17d3505a5 100644 --- a/common.gypi +++ b/common.gypi @@ -55,8 +55,6 @@ # Refs: https://github.com/nodejs/node/issues/23167 # Enable compiler warnings when using V8_DEPRECATED apis from V8 code. 'v8_deprecation_warnings': 0, - # Check that JavaScript execution is disallowed in V8 API interrupts. - 'v8_disallow_js_in_api_interrupts_is_checked': 1, # Enable compiler warnings when using V8_DEPRECATE_SOON apis from V8 code. 'v8_imminent_deprecation_warnings': 0, @@ -537,9 +535,6 @@ ['v8_deprecation_warnings == 1', { 'defines': ['V8_DEPRECATION_WARNINGS',], }], - ['v8_disallow_js_in_api_interrupts_is_checked == 1', { - 'defines': ['V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED',], - }], ['v8_imminent_deprecation_warnings == 1', { 'defines': ['V8_IMMINENT_DEPRECATION_WARNINGS',], }], diff --git a/tools/v8_gypfiles/features.gypi b/tools/v8_gypfiles/features.gypi index 9c8c94a17082..d656c7492dec 100644 --- a/tools/v8_gypfiles/features.gypi +++ b/tools/v8_gypfiles/features.gypi @@ -107,9 +107,6 @@ # Enable compiler warnings when using V8_DEPRECATED apis. 'v8_deprecation_warnings%': 0, - # Check that JavaScript execution is disallowed in V8 API interrupts. - 'v8_disallow_js_in_api_interrupts_is_checked%': 0, - # Enable compiler warnings when using V8_DEPRECATE_SOON apis. 'v8_imminent_deprecation_warnings%': 0, @@ -420,9 +417,6 @@ ['v8_deprecation_warnings==1', { 'defines': ['V8_DEPRECATION_WARNINGS',], }], - ['v8_disallow_js_in_api_interrupts_is_checked==1', { - 'defines': ['V8_DISALLOW_JS_IN_API_INTERRUPTS_IS_CHECKED',], - }], ['v8_imminent_deprecation_warnings==1', { 'defines': ['V8_IMMINENT_DEPRECATION_WARNINGS',], }], From f4ae6b893526389859a573a5bfc2bfbddfd71b0f Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 8 Sep 2026 11:26:27 +0200 Subject: [PATCH 3/3] Revert "inspector: defer JS execution from V8 interrupts" This reverts commit 30f4990224486be3502f94202e6c0e706163b315. --- src/inspector_agent.cc | 183 ++++++++++++++++++---------------------- src/inspector_agent.h | 18 ++-- src/inspector_js_api.cc | 46 +++------- 3 files changed, 102 insertions(+), 145 deletions(-) diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index 83d3398da36b..dcec24c16dba 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -79,52 +79,6 @@ static std::atomic_bool start_io_thread_async_initialized { false }; // Protects the Agent* stored in start_io_thread_async.data. static Mutex start_io_thread_async_mutex; -template -void SyncJavaScriptHookState(Environment* env, - JavaScriptHookState* state, - Local enable_function, - Local disable_function, - bool require_bootstrapping, - Defer defer, - OnFailure on_failure) { - // The debugger can request an interrupt from within a hook's JS toggle - // function. A nested sync only records the new requested state; the - // outermost sync sees it when re-checking the loop after each toggle. - if (state->syncing) return; - state->syncing = true; - auto on_exit = OnScopeLeave([state]() { state->syncing = false; }); - - Isolate* isolate = env->isolate(); - while (state->wanted != state->enabled) { - // No hook events will be emitted during cleanup, and calling into JS is no - // longer possible. - // Refs: https://github.com/nodejs/node/pull/34362#discussion_r456006039 - if (!env->can_call_into_js()) return; - - bool enable = state->wanted; - Local function = enable ? enable_function : disable_function; - if (function.IsEmpty()) return; - - if (env->is_processing_v8_interrupt()) { - defer(); - return; - } - - if (require_bootstrapping) CHECK(env->has_run_bootstrapping_code()); - Local context = env->context(); - v8::TryCatch try_catch(isolate); - USE(function->Call(context, Undefined(isolate), 0, nullptr)); - if (try_catch.HasCaught()) { - // Termination may abort the toggle invocation. Do not record a state that - // may not have taken effect, so a later sync can retry it. - if (try_catch.HasTerminated()) return; - PrintCaughtException(isolate, context, try_catch); - on_failure(); - } - state->enabled = enable; - } -} - // Called on the main thread. void StartIoThreadAsyncCallback(uv_async_t* handle) { static_cast(handle->data)->StartIoThread(); @@ -521,16 +475,6 @@ class SameThreadInspectorSession : public InspectorSession { void NotifyClusterWorkersDebugEnabled(Environment* env) { Isolate* isolate = env->isolate(); - - // Starting the inspector from an interrupt is safe, but emitting the cluster - // notification calls into JS. - if (env->is_processing_v8_interrupt()) { - env->SetImmediate( - [](Environment* env) { NotifyClusterWorkersDebugEnabled(env); }, - CallbackFlags::kUnrefed); - return; - } - HandleScope handle_scope(isolate); // Send message to enable debug in cluster workers @@ -1037,40 +981,54 @@ void Agent::SetupNetworkTracking(Local enable_function, Local disable_function) { parent_env_->set_inspector_enable_network_tracking(enable_function); parent_env_->set_inspector_disable_network_tracking(disable_function); - SyncNetworkTrackingState(); + if (pending_enable_network_tracking) { + pending_enable_network_tracking = false; + EnableNetworkTracking(); + } else if (pending_disable_network_tracking) { + pending_disable_network_tracking = false; + DisableNetworkTracking(); + } } void Agent::EnableNetworkTracking() { - network_tracking_state_.wanted = true; - SyncNetworkTrackingState(); + if (network_tracking_enabled_) { + return; + } + HandleScope scope(parent_env_->isolate()); + Local enable = parent_env_->inspector_enable_network_tracking(); + if (enable.IsEmpty()) { + pending_enable_network_tracking = true; + } else { + ToggleNetworkTracking(parent_env_->isolate(), enable); + network_tracking_enabled_ = true; + } } void Agent::DisableNetworkTracking() { - if (client_->hasConnectedSessions()) return; - network_tracking_state_.wanted = false; - SyncNetworkTrackingState(); + if (!network_tracking_enabled_) { + return; + } + HandleScope scope(parent_env_->isolate()); + Local disable = parent_env_->inspector_disable_network_tracking(); + if (disable.IsEmpty()) { + pending_disable_network_tracking = true; + } else if (!client_->hasConnectedSessions()) { + ToggleNetworkTracking(parent_env_->isolate(), disable); + network_tracking_enabled_ = false; + } } -void Agent::SyncNetworkTrackingState() { - Isolate* isolate = parent_env_->isolate(); +void Agent::ToggleNetworkTracking(Isolate* isolate, Local fn) { + if (!parent_env_->can_call_into_js()) return; + auto context = parent_env_->context(); HandleScope scope(isolate); - SyncJavaScriptHookState( - parent_env_, - &network_tracking_state_, - parent_env_->inspector_enable_network_tracking(), - parent_env_->inspector_disable_network_tracking(), - false, - [this]() { - parent_env_->SetImmediate( - [](Environment* env) { - Agent* agent = env->inspector_agent(); - if (agent != nullptr) agent->SyncNetworkTrackingState(); - }, - CallbackFlags::kUnrefed); - }, - []() { - UNREACHABLE("Cannot toggle network tracking, please report this."); - }); + CHECK(!fn.IsEmpty()); + v8::TryCatch try_catch(isolate); + USE(fn->Call(context, Undefined(isolate), 0, nullptr)); + if (try_catch.HasCaught() && !try_catch.HasTerminated()) { + PrintCaughtException(isolate, context, try_catch); + UNREACHABLE("Cannot toggle network tracking, please report this."); + } } void Agent::WaitForDisconnect() { @@ -1121,7 +1079,7 @@ void Agent::RegisterAsyncHook(Isolate* isolate, } void Agent::SetAsyncHookTrackingEnabled(bool enabled) { - async_hook_state_.wanted = enabled; + async_hook_wanted_ = enabled; SyncAsyncHookState(); } @@ -1135,25 +1093,52 @@ void Agent::SetAsyncHookTrackingEnabled(bool enabled) { // When it's not safe to call into JS, this is a no-op and we'll try again in // RegisterAsyncHook() (for 1) or from a scheduled immediate (for 2). void Agent::SyncAsyncHookState() { + // The debugger can request an interrupt within the toggle JS function itself, + // A nested call only records the new requested state, the outermost call sees + // it when re-checking the loop condition after each toggle. + if (syncing_async_hook_state_) return; + syncing_async_hook_state_ = true; + auto on_exit = OnScopeLeave([this]() { syncing_async_hook_state_ = false; }); + Isolate* isolate = parent_env_->isolate(); HandleScope scope(isolate); - SyncJavaScriptHookState( - parent_env_, - &async_hook_state_, - parent_env_->inspector_enable_async_hooks(), - parent_env_->inspector_disable_async_hooks(), - true, - [this]() { - parent_env_->SetImmediate( - [](Environment* env) { - Agent* agent = env->inspector_agent(); - if (agent != nullptr) agent->SyncAsyncHookState(); - }, - CallbackFlags::kUnrefed); - }, - []() { - UNREACHABLE("Cannot toggle Inspector's AsyncHook, please report this."); - }); + while (async_hook_wanted_ != async_hook_enabled_) { + // Guard against running this during cleanup -- no async events will be + // emitted anyway at that point anymore, and calling into JS is not + // possible. This should probably not be something we're attempting in the + // first place, + // Refs: https://github.com/nodejs/node/pull/34362#discussion_r456006039 + if (!parent_env_->can_call_into_js()) return; + + bool enable = async_hook_wanted_; + Local fn = enable ? parent_env_->inspector_enable_async_hooks() + : parent_env_->inspector_disable_async_hooks(); + if (fn.IsEmpty()) return; + + if (parent_env_->is_processing_v8_interrupt()) { + parent_env_->SetImmediate( + [](Environment* env) { + Agent* agent = env->inspector_agent(); + if (agent != nullptr) agent->SyncAsyncHookState(); + }, + CallbackFlags::kUnrefed); + return; + } + + CHECK(parent_env_->has_run_bootstrapping_code()); + Local context = parent_env_->context(); + v8::TryCatch try_catch(isolate); + USE(fn->Call(context, Undefined(isolate), 0, nullptr)); + if (try_catch.HasCaught()) { + // Termination may abort the toggle invocation, retrying now would just + // be terminated again. Instead of recording the toggle that may not have + // taken effect, leave the states as-is so that a later sync retries. + if (try_catch.HasTerminated()) return; + PrintCaughtException(isolate, context, try_catch); + UNREACHABLE("Cannot toggle Inspector's AsyncHook, please report this."); + } + async_hook_enabled_ = enable; + } } void Agent::AsyncTaskScheduled(const StringView& task_name, void* task, diff --git a/src/inspector_agent.h b/src/inspector_agent.h index 73835d2a4d1d..932e4e8dce89 100644 --- a/src/inspector_agent.h +++ b/src/inspector_agent.h @@ -28,12 +28,6 @@ class ParentInspectorHandle; class NodeInspectorClient; class WorkerManager; -struct JavaScriptHookState { - bool wanted = false; - bool enabled = false; - bool syncing = false; -}; - class InspectorSession { public: virtual ~InspectorSession() = default; @@ -138,7 +132,7 @@ class Agent { private: void SyncAsyncHookState(); - void SyncNetworkTrackingState(); + void ToggleNetworkTracking(v8::Isolate* isolate, v8::Local fn); node::Environment* parent_env_; // Encapsulates majority of the Inspector functionality @@ -158,11 +152,13 @@ class Agent { // The state of the async hook used for async stack traces that the protocol // last requested, and the state JS currently has. SyncAsyncHookState() // reconciles the two when it is possible and safe to call into JS. - JavaScriptHookState async_hook_state_; + bool async_hook_wanted_ = false; + bool async_hook_enabled_ = false; + bool syncing_async_hook_state_ = false; - // Network tracking uses JS hooks. Reconcile the protocol requested and - // applied states after leaving a V8 interrupt. - JavaScriptHookState network_tracking_state_; + bool network_tracking_enabled_ = false; + bool pending_enable_network_tracking = false; + bool pending_disable_network_tracking = false; std::shared_ptr network_resource_manager_; }; diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc index 09f0d7e84ce6..ef1f99d7f38a 100644 --- a/src/inspector_js_api.cc +++ b/src/inspector_js_api.cc @@ -60,31 +60,13 @@ struct MainThreadConnection { template class JSBindingsConnection : public BaseObject { public: - struct PendingMicrotask { - explicit PendingMicrotask(JSBindingsConnection* connection) - : env(connection->env()), connection(connection) { - env->AddCleanupHook(Delete, this); - } - - static void Delete(void* data) { - delete static_cast(data); - } - - static void Run(void* data) { - std::unique_ptr pending( - static_cast(data)); - pending->env->RemoveCleanupHook(Delete, pending.get()); - pending->connection->FlushPendingMessages(); - } - - Environment* env; - BaseObjectPtr connection; - }; - class JSBindingsSessionDelegate : public InspectorSessionDelegate { public: - explicit JSBindingsSessionDelegate(JSBindingsConnection* connection) - : connection_(connection) {} + JSBindingsSessionDelegate(Environment* env, + JSBindingsConnection* connection) + : env_(env), + connection_(connection) { + } void SendMessageToFrontend(const v8_inspector::StringView& message) override { @@ -92,6 +74,7 @@ class JSBindingsConnection : public BaseObject { } private: + Environment* env_; BaseObjectPtr connection_; }; @@ -101,10 +84,10 @@ class JSBindingsConnection : public BaseObject { : BaseObject(env, wrap), callback_(env->isolate(), callback) { Agent* inspector = env->inspector_agent(); session_ = ConnectionType::Connect( - inspector, std::make_unique(this)); - // Inspector responses may be produced from a GC weak callback or a V8 - // interrupt, where invoking the JavaScript session callback is forbidden. - // Defer delivery until it is safe to call into JavaScript. + inspector, std::make_unique(env, this)); + // Inspector responses may be produced from a GC weak callback, where + // invoking the JavaScript session callback is forbidden. Defer delivery + // until the GC has completed. env->isolate()->AddGCPrologueCallback(GCPrologueCallback, this); env->isolate()->AddGCEpilogueCallback(GCEpilogueCallback, this); } @@ -115,8 +98,7 @@ class JSBindingsConnection : public BaseObject { } void SendMessageToFrontend(const v8_inspector::StringView& message) { - if (in_gc_ || env()->is_processing_v8_interrupt() || delivering_ || - !pending_messages_.empty()) { + if (in_gc_ || delivering_ || !pending_messages_.empty()) { pending_messages_.emplace_back( message.is8Bit() ? std::u16string(message.characters8(), @@ -144,12 +126,6 @@ class JSBindingsConnection : public BaseObject { void ScheduleFlush() { if (flush_scheduled_ || delivering_) return; flush_scheduled_ = true; - if (!in_gc_ && env()->is_processing_v8_interrupt()) { - auto* pending = new PendingMicrotask(this); - env()->context()->GetMicrotaskQueue()->EnqueueMicrotask( - env()->isolate(), PendingMicrotask::Run, pending); - return; - } BaseObjectPtr strong_ref{this}; env()->SetImmediate( [strong_ref](Environment*) { strong_ref->FlushPendingMessages(); },