1// Copyright 2018 the V8 project authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#ifndef V8_EXECUTION_MICROTASK_QUEUE_H_ 6#define V8_EXECUTION_MICROTASK_QUEUE_H_ 7 8#include <stdint.h> 9 10#include <memory> 11#include <vector> 12 13#include "include/v8-internal.h" // For Address. 14#include "include/v8-microtask-queue.h" 15#include "src/base/macros.h" 16 17namespace v8 { 18namespace internal { 19 20class Isolate; 21class Microtask; 22class Object; 23class RootVisitor; 24 25class V8_EXPORT_PRIVATE MicrotaskQueue final : public v8::MicrotaskQueue { 26 public: 27 static void SetUpDefaultMicrotaskQueue(Isolate* isolate); 28 static std::unique_ptr<MicrotaskQueue> New(Isolate* isolate); 29 30 ~MicrotaskQueue() override; 31 32 // Uses raw Address values because it's called via ExternalReference. 33 // {raw_microtask} is a tagged Microtask pointer. 34 // Returns Smi::kZero due to CallCFunction. 35 static Address CallEnqueueMicrotask(Isolate* isolate, 36 intptr_t microtask_queue_pointer, 37 Address raw_microtask); 38 39 // v8::MicrotaskQueue implementations. 40 void EnqueueMicrotask(v8::Isolate* isolate, 41 v8::Local<Function> microtask) override; 42 void EnqueueMicrotask(v8::Isolate* isolate, v8::MicrotaskCallback callback, 43 void* data) override; 44 void PerformCheckpoint(v8::Isolate* isolate) override { 45 if (!ShouldPerfomCheckpoint()) return; 46 PerformCheckpointInternal(isolate); 47 } 48 49 bool ShouldPerfomCheckpoint() const { 50 return !IsRunningMicrotasks() && !GetMicrotasksScopeDepth() && 51 !HasMicrotasksSuppressions(); 52 } 53 54 void EnqueueMicrotask(Microtask microtask); 55 void AddMicrotasksCompletedCallback( 56 MicrotasksCompletedCallbackWithData callback, void* data) override; 57 void RemoveMicrotasksCompletedCallback( 58 MicrotasksCompletedCallbackWithData callback, void* data) override; 59 bool IsRunningMicrotasks() const override { return is_running_microtasks_; } 60 61 // Runs all queued Microtasks. 62 // Returns -1 if the execution is terminating, otherwise, returns the number 63 // of microtasks that ran in this round. 64 int RunMicrotasks(Isolate* isolate); 65 66 // Iterate all pending Microtasks in this queue as strong roots, so that 67 // builtins can update the queue directly without the write barrier. 68 void IterateMicrotasks(RootVisitor* visitor); 69 70 // Microtasks scope depth represents nested scopes controlling microtasks 71 // invocation, which happens when depth reaches zero. 72 void IncrementMicrotasksScopeDepth() { ++microtasks_depth_; } 73 void DecrementMicrotasksScopeDepth() { --microtasks_depth_; } 74 int GetMicrotasksScopeDepth() const override { return microtasks_depth_; } 75 76 // Possibly nested microtasks suppression scopes prevent microtasks 77 // from running. 78 void IncrementMicrotasksSuppressions() { ++microtasks_suppressions_; } 79 void DecrementMicrotasksSuppressions() { --microtasks_suppressions_; } 80 bool HasMicrotasksSuppressions() const { 81 return microtasks_suppressions_ != 0; 82 } 83 84#ifdef DEBUG 85 // In debug we check that calls not intended to invoke microtasks are 86 // still correctly wrapped with microtask scopes. 87 void IncrementDebugMicrotasksScopeDepth() { ++debug_microtasks_depth_; } 88 void DecrementDebugMicrotasksScopeDepth() { --debug_microtasks_depth_; } 89 bool DebugMicrotasksScopeDepthIsZero() const { 90 return debug_microtasks_depth_ == 0; 91 } 92#endif 93 94 void set_microtasks_policy(v8::MicrotasksPolicy microtasks_policy) { 95 microtasks_policy_ = microtasks_policy; 96 } 97 v8::MicrotasksPolicy microtasks_policy() const { return microtasks_policy_; } 98 99 intptr_t capacity() const { return capacity_; } 100 intptr_t size() const { return size_; } 101 intptr_t start() const { return start_; } 102 103 Microtask get(intptr_t index) const; 104 105 MicrotaskQueue* next() const { return next_; } 106 MicrotaskQueue* prev() const { return prev_; } 107 108 static const size_t kRingBufferOffset; 109 static const size_t kCapacityOffset; 110 static const size_t kSizeOffset; 111 static const size_t kStartOffset; 112 static const size_t kFinishedMicrotaskCountOffset; 113 114 static const intptr_t kMinimumCapacity; 115 116 private: 117 void PerformCheckpointInternal(v8::Isolate* v8_isolate); 118 119 void OnCompleted(Isolate* isolate) const; 120 121 MicrotaskQueue(); 122 void ResizeBuffer(intptr_t new_capacity); 123 124 // A ring buffer to hold Microtask instances. 125 // ring_buffer_[(start_ + i) % capacity_] contains |i|th Microtask for each 126 // |i| in [0, size_). 127 intptr_t size_ = 0; 128 intptr_t capacity_ = 0; 129 intptr_t start_ = 0; 130 Address* ring_buffer_ = nullptr; 131 132 // The number of finished microtask. 133 intptr_t finished_microtask_count_ = 0; 134 135 // MicrotaskQueue instances form a doubly linked list loop, so that all 136 // instances are reachable through |next_|. 137 MicrotaskQueue* next_ = nullptr; 138 MicrotaskQueue* prev_ = nullptr; 139 140 int microtasks_depth_ = 0; 141 int microtasks_suppressions_ = 0; 142#ifdef DEBUG 143 int debug_microtasks_depth_ = 0; 144#endif 145 146 v8::MicrotasksPolicy microtasks_policy_ = v8::MicrotasksPolicy::kAuto; 147 148 bool is_running_microtasks_ = false; 149 using CallbackWithData = 150 std::pair<MicrotasksCompletedCallbackWithData, void*>; 151 std::vector<CallbackWithData> microtasks_completed_callbacks_; 152}; 153 154} // namespace internal 155} // namespace v8 156 157#endif // V8_EXECUTION_MICROTASK_QUEUE_H_ 158