Skip to content

Commit 19b35bc

Browse files
committed
deps: V8: cherry-pick 25650aa994
Original commit message: [microtask] Early-exit empty PerformCheckpointInternal and OnCompleted Microtask checkpoints (MicrotaskQueue::PerformCheckpoint) are executed frequently at the end of every DOM event listener, microtask scope exit, timer callback, and mutation observer turn. In typical DOM interactions and event dispatch cycles, the microtask queue is frequently empty (size_ == 0), no microtask completion callbacks are registered, and no weak references were kept during the job (weak_refs_keep_during_job == undefined_value()). Previously, even when the queue was empty, PerformCheckpointInternal unconditionally allocated an artificial MicrotasksScope(kDoNotRunMicrotasks), called RunMicrotasks (which set running state flags, created suppress scopes, and rewound entered contexts), invoked OnCompleted, and called isolate->ClearKeptObjects() (performing an unconditional store to the weak_refs_keep_during_job root table slot). This CL fast-paths PerformCheckpointInternal when size() == 0, microtasks_completed_callbacks_ is empty, and weak_refs_keep_during_job is undefined. If WeakRef.prototype.deref() was invoked during the turn, weak_refs_keep_during_job holds an OrderedHashSet, so the early-exit is skipped and ClearKeptObjects() runs to clear kept objects as required by ECMAScript §26.1. Pinpoint Try Job on Apple Silicon M1 (150 iterations, Job 158c2910690000): - Speedometer 3 Score: 31.42 -> 31.48 (+0.21%, p=0.0293, stat-sig win) - TodoMVC-JavaScript-ES6-Webpack: -0.87% (p=0.0001) - NewsSite-Nuxt: -0.40% (p=0.0001) - TodoMVC-Angular: -0.45% (p=0.0681) - TodoMVC-jQuery: -0.36% (p=0.6023) - Charts-chartjs: -0.21% (p=0.0005) - React-Stockcharts-SVG: -0.26% (p=0.0144) Bug: 553846289 TAG=agy CONV=a3721850-14cb-425b-8d34-169f9934ed78 Change-Id: Ic996d283b746a5684a55c9fbc56d8fcfb38ac299 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8312487 Commit-Queue: Anton Bikineev <bikineev@chromium.org> Auto-Submit: Anton Bikineev <bikineev@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/main@{#109567} Refs: v8/v8@25650aa Signed-off-by: Nigro Simone <nigro.simone@gmail.com>
1 parent ad55417 commit 19b35bc

2 files changed

Lines changed: 21 additions & 3 deletions

File tree

‎common.gypi‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545
# Reset this number to 0 on major V8 upgrades.
4646
# Increment by one for each non-official patch applied to deps/v8.
47-
'v8_embedder_string': '-node.22',
47+
'v8_embedder_string': '-node.23',
4848

4949
##### V8 defaults for Node.js #####
5050

‎deps/v8/src/execution/microtask-queue.cc‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "src/execution/isolate.h"
2020
#include "src/handles/handle-scope-implementer-inl.h"
2121
#include "src/handles/handles-inl.h"
22+
#include "src/heap/heap-inl.h"
2223
#include "src/objects/microtask-inl.h"
2324
#include "src/objects/visitors.h"
2425
#include "src/roots/roots-inl.h"
@@ -165,6 +166,18 @@ void MicrotaskQueue::EnqueueMicrotask(Tagged<Microtask> microtask) {
165166

166167
void MicrotaskQueue::PerformCheckpointInternal(v8::Isolate* v8_isolate) {
167168
DCHECK(ShouldPerfomCheckpoint());
169+
DCHECK(!microtasks_completed_callbacks_cow_.has_value());
170+
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
171+
// Fast path: Checkpoints occur frequently when exiting script or microtask
172+
// scopes. If there are no microtasks to drain, no completion callbacks to
173+
// notify, and no kept objects from FinalizationRegistry / WeakRefs to clear,
174+
// we can bail out immediately and avoid artificial MicrotasksScope setup and
175+
// RunMicrotasks overhead.
176+
if (size() == 0 && microtasks_completed_callbacks_.empty() &&
177+
isolate->heap()->weak_refs_keep_during_job() ==
178+
ReadOnlyRoots(isolate).undefined_value()) [[likely]] {
179+
return;
180+
}
168181
std::optional<MicrotasksScope> microtasks_scope;
169182
if (microtasks_policy_ == v8::MicrotasksPolicy::kScoped) {
170183
// If we're using microtask scopes to schedule microtask execution, V8
@@ -175,7 +188,6 @@ void MicrotaskQueue::PerformCheckpointInternal(v8::Isolate* v8_isolate) {
175188
microtasks_scope.emplace(v8_isolate, this,
176189
v8::MicrotasksScope::kDoNotRunMicrotasks);
177190
}
178-
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
179191
RunMicrotasks(isolate);
180192
isolate->ClearKeptObjects();
181193
}
@@ -347,12 +359,18 @@ void MicrotaskQueue::RemoveMicrotasksCompletedCallback(
347359
}
348360

349361
void MicrotaskQueue::OnCompleted(Isolate* isolate) {
362+
DCHECK_IMPLIES(microtasks_completed_callbacks_.empty(),
363+
!microtasks_completed_callbacks_cow_.has_value());
364+
if (microtasks_completed_callbacks_.empty()) [[likely]] {
365+
return;
366+
}
367+
350368
is_running_completed_callbacks_ = true;
351369
for (auto& callback : microtasks_completed_callbacks_) {
352370
callback.first(reinterpret_cast<v8::Isolate*>(isolate), callback.second);
353371
}
354372
is_running_completed_callbacks_ = false;
355-
if (V8_UNLIKELY(microtasks_completed_callbacks_cow_.has_value())) {
373+
if (microtasks_completed_callbacks_cow_.has_value()) [[unlikely]] {
356374
microtasks_completed_callbacks_ =
357375
std::move(microtasks_completed_callbacks_cow_.value());
358376
microtasks_completed_callbacks_cow_.reset();

0 commit comments

Comments
 (0)