[runtime][microtask] Various smaller performance tweaks

- Make sure we use fast prechecks in the header files
- MicrotaskQueue::CallEnqueueMicrotask returns a Smi instead of a
  more costly undefined value (the return value is enforced by the
  calling convention, but unused)
- Merge FireMicrotasksCompletedCallback into OnComplete

Change-Id: I3797b946bcffb6349e5693c41478bd2bad1f93fb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3024154
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75985}
This commit is contained in:
Camillo Bruni 2021-07-29 11:03:44 +02:00 committed by V8 LUCI CQ
parent 02ba58d59d
commit 1d249e8cb4
4 changed files with 39 additions and 35 deletions

View File

@ -4212,8 +4212,9 @@ void Isolate::RemoveCallCompletedCallback(CallCompletedCallback callback) {
call_completed_callbacks_.erase(pos);
}
void Isolate::FireCallCompletedCallback(MicrotaskQueue* microtask_queue) {
if (!thread_local_top()->CallDepthIsZero()) return;
void Isolate::FireCallCompletedCallbackInternal(
MicrotaskQueue* microtask_queue) {
DCHECK(thread_local_top()->CallDepthIsZero());
bool perform_checkpoint =
microtask_queue &&

View File

@ -1452,7 +1452,10 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
size_t heap_limit);
void AddCallCompletedCallback(CallCompletedCallback callback);
void RemoveCallCompletedCallback(CallCompletedCallback callback);
void FireCallCompletedCallback(MicrotaskQueue* microtask_queue);
void FireCallCompletedCallback(MicrotaskQueue* microtask_queue) {
if (!thread_local_top()->CallDepthIsZero()) return;
FireCallCompletedCallbackInternal(microtask_queue);
}
void AddBeforeCallEnteredCallback(BeforeCallEnteredCallback callback);
void RemoveBeforeCallEnteredCallback(BeforeCallEnteredCallback callback);
@ -1830,6 +1833,8 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
static void RemoveContextIdCallback(const v8::WeakCallbackInfo<void>& data);
void FireCallCompletedCallbackInternal(MicrotaskQueue* microtask_queue);
class ThreadDataTable {
public:
ThreadDataTable() = default;

View File

@ -74,7 +74,7 @@ Address MicrotaskQueue::CallEnqueueMicrotask(Isolate* isolate,
Microtask microtask = Microtask::cast(Object(raw_microtask));
reinterpret_cast<MicrotaskQueue*>(microtask_queue_pointer)
->EnqueueMicrotask(microtask);
return ReadOnlyRoots(isolate).undefined_value().ptr();
return Smi::zero().ptr();
}
void MicrotaskQueue::EnqueueMicrotask(v8::Isolate* v8_isolate,
@ -110,23 +110,21 @@ void MicrotaskQueue::EnqueueMicrotask(Microtask microtask) {
++size_;
}
void MicrotaskQueue::PerformCheckpoint(v8::Isolate* v8_isolate) {
if (!IsRunningMicrotasks() && !GetMicrotasksScopeDepth() &&
!HasMicrotasksSuppressions()) {
std::unique_ptr<MicrotasksScope> microtasks_scope;
if (microtasks_policy_ == v8::MicrotasksPolicy::kScoped) {
// If we're using microtask scopes to schedule microtask execution, V8
// API calls will check that there's always a microtask scope on the
// stack. As the microtasks we're about to execute could invoke embedder
// callbacks which then calls back into V8, we create an artificial
// microtask scope here to avoid running into the CallDepthScope check.
microtasks_scope.reset(new v8::MicrotasksScope(
v8_isolate, this, v8::MicrotasksScope::kDoNotRunMicrotasks));
}
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
RunMicrotasks(isolate);
isolate->ClearKeptObjects();
void MicrotaskQueue::PerformCheckpointInternal(v8::Isolate* v8_isolate) {
DCHECK(ShouldPerfomCheckpoint());
std::unique_ptr<MicrotasksScope> microtasks_scope;
if (microtasks_policy_ == v8::MicrotasksPolicy::kScoped) {
// If we're using microtask scopes to schedule microtask execution, V8
// API calls will check that there's always a microtask scope on the
// stack. As the microtasks we're about to execute could invoke embedder
// callbacks which then calls back into V8, we create an artificial
// microtask scope here to avoid running into the CallDepthScope check.
microtasks_scope.reset(new v8::MicrotasksScope(
v8_isolate, this, v8::MicrotasksScope::kDoNotRunMicrotasks));
}
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
RunMicrotasks(isolate);
isolate->ClearKeptObjects();
}
namespace {
@ -226,10 +224,6 @@ void MicrotaskQueue::IterateMicrotasks(RootVisitor* visitor) {
}
}
int MicrotaskQueue::GetMicrotasksScopeDepth() const {
return microtasks_depth_;
}
void MicrotaskQueue::AddMicrotasksCompletedCallback(
MicrotasksCompletedCallbackWithData callback, void* data) {
CallbackWithData callback_with_data(callback, data);
@ -250,7 +244,7 @@ void MicrotaskQueue::RemoveMicrotasksCompletedCallback(
microtasks_completed_callbacks_.erase(pos);
}
void MicrotaskQueue::FireMicrotasksCompletedCallback(Isolate* isolate) const {
void MicrotaskQueue::OnCompleted(Isolate* isolate) const {
std::vector<CallbackWithData> callbacks(microtasks_completed_callbacks_);
for (auto& callback : callbacks) {
callback.first(reinterpret_cast<v8::Isolate*>(isolate), callback.second);
@ -263,10 +257,6 @@ Microtask MicrotaskQueue::get(intptr_t index) const {
return Microtask::cast(microtask);
}
void MicrotaskQueue::OnCompleted(Isolate* isolate) {
FireMicrotasksCompletedCallback(isolate);
}
void MicrotaskQueue::ResizeBuffer(intptr_t new_capacity) {
DCHECK_LE(size_, new_capacity);
Address* new_ring_buffer = new Address[new_capacity];

View File

@ -30,7 +30,7 @@ class V8_EXPORT_PRIVATE MicrotaskQueue final : public v8::MicrotaskQueue {
// Uses raw Address values because it's called via ExternalReference.
// {raw_microtask} is a tagged Microtask pointer.
// Returns a tagged Object pointer.
// Returns Smi::kZero due to CallCFunction.
static Address CallEnqueueMicrotask(Isolate* isolate,
intptr_t microtask_queue_pointer,
Address raw_microtask);
@ -40,7 +40,15 @@ class V8_EXPORT_PRIVATE MicrotaskQueue final : public v8::MicrotaskQueue {
v8::Local<Function> microtask) override;
void EnqueueMicrotask(v8::Isolate* isolate, v8::MicrotaskCallback callback,
void* data) override;
void PerformCheckpoint(v8::Isolate* isolate) override;
void PerformCheckpoint(v8::Isolate* isolate) override {
if (!ShouldPerfomCheckpoint()) return;
PerformCheckpointInternal(isolate);
}
bool ShouldPerfomCheckpoint() const {
return !IsRunningMicrotasks() && !GetMicrotasksScopeDepth() &&
!HasMicrotasksSuppressions();
}
void EnqueueMicrotask(Microtask microtask);
void AddMicrotasksCompletedCallback(
@ -62,7 +70,7 @@ class V8_EXPORT_PRIVATE MicrotaskQueue final : public v8::MicrotaskQueue {
// invocation, which happens when depth reaches zero.
void IncrementMicrotasksScopeDepth() { ++microtasks_depth_; }
void DecrementMicrotasksScopeDepth() { --microtasks_depth_; }
int GetMicrotasksScopeDepth() const override;
int GetMicrotasksScopeDepth() const override { return microtasks_depth_; }
// Possibly nested microtasks suppression scopes prevent microtasks
// from running.
@ -87,8 +95,6 @@ class V8_EXPORT_PRIVATE MicrotaskQueue final : public v8::MicrotaskQueue {
}
v8::MicrotasksPolicy microtasks_policy() const { return microtasks_policy_; }
void FireMicrotasksCompletedCallback(Isolate* isolate) const;
intptr_t capacity() const { return capacity_; }
intptr_t size() const { return size_; }
intptr_t start() const { return start_; }
@ -107,7 +113,9 @@ class V8_EXPORT_PRIVATE MicrotaskQueue final : public v8::MicrotaskQueue {
static const intptr_t kMinimumCapacity;
private:
void OnCompleted(Isolate* isolate);
void PerformCheckpointInternal(v8::Isolate* v8_isolate);
void OnCompleted(Isolate* isolate) const;
MicrotaskQueue();
void ResizeBuffer(intptr_t new_capacity);