1ab717db84
Blink used to use v8::MicrotasksScope::GetCurrentDepth() to get the number of nested MicrotasksScope for the default microtask queue. However, there was no corresponding one for non-default queues. Change-Id: I1c2472ba19b1a11cb968f02119d91d92867c6e02 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1567705 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Commit-Queue: Taiju Tsuiki <tzik@chromium.org> Cr-Commit-Position: refs/heads/master@{#60862}
149 lines
5.0 KiB
C++
149 lines
5.0 KiB
C++
// Copyright 2018 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.
|
|
|
|
#ifndef V8_MICROTASK_QUEUE_H_
|
|
#define V8_MICROTASK_QUEUE_H_
|
|
|
|
#include <stdint.h>
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "include/v8-internal.h" // For Address.
|
|
#include "include/v8.h"
|
|
#include "src/base/macros.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
class Isolate;
|
|
class Microtask;
|
|
class Object;
|
|
class RootVisitor;
|
|
|
|
class V8_EXPORT_PRIVATE MicrotaskQueue final : public v8::MicrotaskQueue {
|
|
public:
|
|
static void SetUpDefaultMicrotaskQueue(Isolate* isolate);
|
|
static std::unique_ptr<MicrotaskQueue> New(Isolate* isolate);
|
|
|
|
~MicrotaskQueue();
|
|
|
|
// Uses raw Address values because it's called via ExternalReference.
|
|
// {raw_microtask} is a tagged Microtask pointer.
|
|
// Returns a tagged Object pointer.
|
|
static Address CallEnqueueMicrotask(Isolate* isolate,
|
|
intptr_t microtask_queue_pointer,
|
|
Address raw_microtask);
|
|
|
|
// v8::MicrotaskQueue implementations.
|
|
void EnqueueMicrotask(v8::Isolate* isolate,
|
|
v8::Local<Function> microtask) override;
|
|
void EnqueueMicrotask(v8::Isolate* isolate, v8::MicrotaskCallback callback,
|
|
void* data) override;
|
|
void PerformCheckpoint(v8::Isolate* isolate) override;
|
|
|
|
void EnqueueMicrotask(Microtask microtask);
|
|
void AddMicrotasksCompletedCallback(
|
|
MicrotasksCompletedCallbackWithData callback, void* data) override;
|
|
void RemoveMicrotasksCompletedCallback(
|
|
MicrotasksCompletedCallbackWithData callback, void* data) override;
|
|
bool IsRunningMicrotasks() const override { return is_running_microtasks_; }
|
|
|
|
// Runs all queued Microtasks.
|
|
// Returns -1 if the execution is terminating, otherwise, returns the number
|
|
// of microtasks that ran in this round.
|
|
int RunMicrotasks(Isolate* isolate);
|
|
|
|
// Iterate all pending Microtasks in this queue as strong roots, so that
|
|
// builtins can update the queue directly without the write barrier.
|
|
void IterateMicrotasks(RootVisitor* visitor);
|
|
|
|
// Microtasks scope depth represents nested scopes controlling microtasks
|
|
// invocation, which happens when depth reaches zero.
|
|
void IncrementMicrotasksScopeDepth() { ++microtasks_depth_; }
|
|
void DecrementMicrotasksScopeDepth() { --microtasks_depth_; }
|
|
int GetMicrotasksScopeDepth() const override;
|
|
|
|
// Possibly nested microtasks suppression scopes prevent microtasks
|
|
// from running.
|
|
void IncrementMicrotasksSuppressions() { ++microtasks_suppressions_; }
|
|
void DecrementMicrotasksSuppressions() { --microtasks_suppressions_; }
|
|
bool HasMicrotasksSuppressions() const {
|
|
return microtasks_suppressions_ != 0;
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// In debug we check that calls not intended to invoke microtasks are
|
|
// still correctly wrapped with microtask scopes.
|
|
void IncrementDebugMicrotasksScopeDepth() { ++debug_microtasks_depth_; }
|
|
void DecrementDebugMicrotasksScopeDepth() { --debug_microtasks_depth_; }
|
|
bool DebugMicrotasksScopeDepthIsZero() const {
|
|
return debug_microtasks_depth_ == 0;
|
|
}
|
|
#endif
|
|
|
|
void set_microtasks_policy(v8::MicrotasksPolicy microtasks_policy) {
|
|
microtasks_policy_ = microtasks_policy;
|
|
}
|
|
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_; }
|
|
|
|
Microtask get(intptr_t index) const;
|
|
|
|
MicrotaskQueue* next() const { return next_; }
|
|
MicrotaskQueue* prev() const { return prev_; }
|
|
|
|
static const size_t kRingBufferOffset;
|
|
static const size_t kCapacityOffset;
|
|
static const size_t kSizeOffset;
|
|
static const size_t kStartOffset;
|
|
static const size_t kFinishedMicrotaskCountOffset;
|
|
|
|
static const intptr_t kMinimumCapacity;
|
|
|
|
private:
|
|
void OnCompleted(Isolate* isolate);
|
|
|
|
MicrotaskQueue();
|
|
void ResizeBuffer(intptr_t new_capacity);
|
|
|
|
// A ring buffer to hold Microtask instances.
|
|
// ring_buffer_[(start_ + i) % capacity_] contains |i|th Microtask for each
|
|
// |i| in [0, size_).
|
|
intptr_t size_ = 0;
|
|
intptr_t capacity_ = 0;
|
|
intptr_t start_ = 0;
|
|
Address* ring_buffer_ = nullptr;
|
|
|
|
// The number of finished microtask.
|
|
intptr_t finished_microtask_count_ = 0;
|
|
|
|
// MicrotaskQueue instances form a doubly linked list loop, so that all
|
|
// instances are reachable through |next_|.
|
|
MicrotaskQueue* next_ = nullptr;
|
|
MicrotaskQueue* prev_ = nullptr;
|
|
|
|
int microtasks_depth_ = 0;
|
|
int microtasks_suppressions_ = 0;
|
|
#ifdef DEBUG
|
|
int debug_microtasks_depth_ = 0;
|
|
#endif
|
|
|
|
v8::MicrotasksPolicy microtasks_policy_ = v8::MicrotasksPolicy::kAuto;
|
|
|
|
bool is_running_microtasks_ = false;
|
|
using CallbackWithData =
|
|
std::pair<MicrotasksCompletedCallbackWithData, void*>;
|
|
std::vector<CallbackWithData> microtasks_completed_callbacks_;
|
|
};
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|
|
|
|
#endif // V8_MICROTASK_QUEUE_H_
|