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 61055 : class V8_EXPORT_PRIVATE 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 : void EnqueueMicrotask(Microtask microtask);
39 :
40 : // Runs all queued Microtasks.
41 : // Returns -1 if the execution is terminating, otherwise, returns the number
42 : // of microtasks that ran in this round.
43 : int RunMicrotasks(Isolate* isolate);
44 :
45 : // Iterate all pending Microtasks in this queue as strong roots, so that
46 : // builtins can update the queue directly without the write barrier.
47 : void IterateMicrotasks(RootVisitor* visitor);
48 :
49 : // Microtasks scope depth represents nested scopes controlling microtasks
50 : // invocation, which happens when depth reaches zero.
51 160143 : void IncrementMicrotasksScopeDepth() { ++microtasks_depth_; }
52 160144 : void DecrementMicrotasksScopeDepth() { --microtasks_depth_; }
53 : int GetMicrotasksScopeDepth() const { return microtasks_depth_; }
54 :
55 : // Possibly nested microtasks suppression scopes prevent microtasks
56 : // from running.
57 51579 : void IncrementMicrotasksSuppressions() { ++microtasks_suppressions_; }
58 51579 : void DecrementMicrotasksSuppressions() { --microtasks_suppressions_; }
59 : bool HasMicrotasksSuppressions() const {
60 : return microtasks_suppressions_ != 0;
61 : }
62 :
63 : #ifdef DEBUG
64 : // In debug we check that calls not intended to invoke microtasks are
65 : // still correctly wrapped with microtask scopes.
66 : void IncrementDebugMicrotasksScopeDepth() { ++debug_microtasks_depth_; }
67 : void DecrementDebugMicrotasksScopeDepth() { --debug_microtasks_depth_; }
68 : bool DebugMicrotasksScopeDepthIsZero() const {
69 : return debug_microtasks_depth_ == 0;
70 : }
71 : #endif
72 :
73 : void set_microtasks_policy(v8::MicrotasksPolicy microtasks_policy) {
74 2252 : microtasks_policy_ = microtasks_policy;
75 : }
76 : v8::MicrotasksPolicy microtasks_policy() const { return microtasks_policy_; }
77 :
78 : void AddMicrotasksCompletedCallback(MicrotasksCompletedCallback callback);
79 : void RemoveMicrotasksCompletedCallback(MicrotasksCompletedCallback callback);
80 : void FireMicrotasksCompletedCallback(Isolate* isolate) const;
81 : bool IsRunningMicrotasks() const { return is_running_microtasks_; }
82 :
83 : intptr_t capacity() const { return capacity_; }
84 : intptr_t size() const { return size_; }
85 : intptr_t start() const { return start_; }
86 :
87 : MicrotaskQueue* next() const { return next_; }
88 : MicrotaskQueue* prev() const { return prev_; }
89 :
90 : static const size_t kRingBufferOffset;
91 : static const size_t kCapacityOffset;
92 : static const size_t kSizeOffset;
93 : static const size_t kStartOffset;
94 : static const size_t kFinishedMicrotaskCountOffset;
95 :
96 : static const intptr_t kMinimumCapacity;
97 :
98 : private:
99 : void OnCompleted(Isolate* isolate);
100 :
101 : MicrotaskQueue();
102 : void ResizeBuffer(intptr_t new_capacity);
103 :
104 : // A ring buffer to hold Microtask instances.
105 : // ring_buffer_[(start_ + i) % capacity_] contains |i|th Microtask for each
106 : // |i| in [0, size_).
107 : intptr_t size_ = 0;
108 : intptr_t capacity_ = 0;
109 : intptr_t start_ = 0;
110 : Address* ring_buffer_ = nullptr;
111 :
112 : // The number of finished microtask.
113 : intptr_t finished_microtask_count_ = 0;
114 :
115 : // MicrotaskQueue instances form a doubly linked list loop, so that all
116 : // instances are reachable through |next_|.
117 : MicrotaskQueue* next_ = nullptr;
118 : MicrotaskQueue* prev_ = nullptr;
119 :
120 : int microtasks_depth_ = 0;
121 : int microtasks_suppressions_ = 0;
122 : #ifdef DEBUG
123 : int debug_microtasks_depth_ = 0;
124 : #endif
125 :
126 : v8::MicrotasksPolicy microtasks_policy_ = v8::MicrotasksPolicy::kAuto;
127 :
128 : bool is_running_microtasks_ = false;
129 : std::vector<MicrotasksCompletedCallback> microtasks_completed_callbacks_;
130 : };
131 :
132 : } // namespace internal
133 : } // namespace v8
134 :
135 : #endif // V8_MICROTASK_QUEUE_H_
|