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 62889 : 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 : // Returns -1 if the execution is terminating, otherwise, returns 0.
41 : // TODO(tzik): Update the implementation to return the number of processed
42 : // microtasks.
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 161734 : void IncrementMicrotasksScopeDepth() { ++microtasks_depth_; }
52 161733 : void DecrementMicrotasksScopeDepth() { --microtasks_depth_; }
53 : int GetMicrotasksScopeDepth() const { return microtasks_depth_; }
54 :
55 : // Possibly nested microtasks suppression scopes prevent microtasks
56 : // from running.
57 52475 : void IncrementMicrotasksSuppressions() { ++microtasks_suppressions_; }
58 52475 : 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 AddMicrotasksCompletedCallback(MicrotasksCompletedCallback callback);
74 : void RemoveMicrotasksCompletedCallback(MicrotasksCompletedCallback callback);
75 : void FireMicrotasksCompletedCallback(Isolate* isolate) const;
76 : bool IsRunningMicrotasks() const { return is_running_microtasks_; }
77 :
78 : intptr_t capacity() const { return capacity_; }
79 : intptr_t size() const { return size_; }
80 : intptr_t start() const { return start_; }
81 :
82 : MicrotaskQueue* next() const { return next_; }
83 : MicrotaskQueue* prev() const { return prev_; }
84 :
85 : static const size_t kRingBufferOffset;
86 : static const size_t kCapacityOffset;
87 : static const size_t kSizeOffset;
88 : static const size_t kStartOffset;
89 :
90 : static const intptr_t kMinimumCapacity;
91 :
92 : private:
93 : void OnCompleted(Isolate* isolate);
94 :
95 : MicrotaskQueue();
96 : void ResizeBuffer(intptr_t new_capacity);
97 :
98 : // A ring buffer to hold Microtask instances.
99 : // ring_buffer_[(start_ + i) % capacity_] contains |i|th Microtask for each
100 : // |i| in [0, size_).
101 : intptr_t size_ = 0;
102 : intptr_t capacity_ = 0;
103 : intptr_t start_ = 0;
104 : Address* ring_buffer_ = nullptr;
105 :
106 : // MicrotaskQueue instances form a doubly linked list loop, so that all
107 : // instances are reachable through |next_|.
108 : MicrotaskQueue* next_ = nullptr;
109 : MicrotaskQueue* prev_ = nullptr;
110 :
111 : int microtasks_depth_ = 0;
112 : int microtasks_suppressions_ = 0;
113 : #ifdef DEBUG
114 : int debug_microtasks_depth_ = 0;
115 : #endif
116 :
117 : bool is_running_microtasks_ = false;
118 : std::vector<MicrotasksCompletedCallback> microtasks_completed_callbacks_;
119 : };
120 :
121 : } // namespace internal
122 : } // namespace v8
123 :
124 : #endif // V8_MICROTASK_QUEUE_H_
|