#ifndef V8_EXECUTION_MICROTASK_QUEUE_H_
#define V8_EXECUTION_MICROTASK_QUEUE_H_
#include <stdint.h>
#include <memory>
#include <vector>
#include "include/v8-internal.h"
#include "include/v8-microtask-queue.h"
#include "src/base/macros.h"
namespace v8 {
namespace internal {
class Isolate;
class Microtask;
class Object;
class RootVisitor;
template <typename T>
class Tagged;
class V8_EXPORT_PRIVATE MicrotaskQueue final : public v8::MicrotaskQueue {
public:
static void SetUpDefaultMicrotaskQueue(Isolate* isolate);
static std::unique_ptr<MicrotaskQueue> New(Isolate* isolate);
~MicrotaskQueue() override;
static Address CallEnqueueMicrotask(Isolate* isolate,
intptr_t microtask_queue_pointer,
Address raw_microtask);
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 {
if (!ShouldPerfomCheckpoint()) return;
PerformCheckpointInternal(isolate);
}
bool ShouldPerfomCheckpoint() const {
return !IsRunningMicrotasks() && !GetMicrotasksScopeDepth() &&
!HasMicrotasksSuppressions();
}
void EnqueueMicrotask(Tagged<Microtask> microtask);
void AddMicrotasksCompletedCallback(
MicrotasksCompletedCallbackWithData callback, void* data) override;
void RemoveMicrotasksCompletedCallback(
MicrotasksCompletedCallbackWithData callback, void* data) override;
bool IsRunningMicrotasks() const override { return is_running_microtasks_; }
int RunMicrotasks(Isolate* isolate);
void IterateMicrotasks(RootVisitor* visitor);
void IncrementMicrotasksScopeDepth() { ++microtasks_depth_; }
void DecrementMicrotasksScopeDepth() { --microtasks_depth_; }
int GetMicrotasksScopeDepth() const override { return microtasks_depth_; }
void IncrementMicrotasksSuppressions() { ++microtasks_suppressions_; }
void DecrementMicrotasksSuppressions() { --microtasks_suppressions_; }
bool HasMicrotasksSuppressions() const {
return microtasks_suppressions_ != 0;
}
#ifdef DEBUG
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_; }
intptr_t capacity() const { return capacity_; }
intptr_t size() const { return size_; }
intptr_t start() const { return start_; }
Tagged<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 PerformCheckpointInternal(v8::Isolate* v8_isolate);
void OnCompleted(Isolate* isolate);
MicrotaskQueue();
void ResizeBuffer(intptr_t new_capacity);
intptr_t size_ = 0;
intptr_t capacity_ = 0;
intptr_t start_ = 0;
Address* ring_buffer_ = nullptr;
intptr_t finished_microtask_count_ = 0;
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;
bool is_running_completed_callbacks_ = false;
using CallbackWithData =
std::pair<MicrotasksCompletedCallbackWithData, void*>;
std::vector<CallbackWithData> microtasks_completed_callbacks_;
std::optional<std::vector<CallbackWithData>>
microtasks_completed_callbacks_cow_;
};
}
}
#endif