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