V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
microtask-queue.cc
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 #include "src/microtask-queue.h"
6 
7 #include <stddef.h>
8 #include <algorithm>
9 
10 #include "src/base/logging.h"
11 #include "src/handles-inl.h"
12 #include "src/isolate.h"
13 #include "src/objects/microtask.h"
14 #include "src/roots-inl.h"
15 #include "src/visitors.h"
16 
17 namespace v8 {
18 namespace internal {
19 
20 const size_t MicrotaskQueue::kRingBufferOffset =
21  offsetof(MicrotaskQueue, ring_buffer_);
22 const size_t MicrotaskQueue::kCapacityOffset =
23  offsetof(MicrotaskQueue, capacity_);
24 const size_t MicrotaskQueue::kSizeOffset = offsetof(MicrotaskQueue, size_);
25 const size_t MicrotaskQueue::kStartOffset = offsetof(MicrotaskQueue, start_);
26 
27 const intptr_t MicrotaskQueue::kMinimumCapacity = 8;
28 
29 // static
30 void MicrotaskQueue::SetUpDefaultMicrotaskQueue(Isolate* isolate) {
31  DCHECK_NULL(isolate->default_microtask_queue());
32 
33  MicrotaskQueue* microtask_queue = new MicrotaskQueue;
34  microtask_queue->next_ = microtask_queue;
35  microtask_queue->prev_ = microtask_queue;
36  isolate->set_default_microtask_queue(microtask_queue);
37 }
38 
39 // static
40 std::unique_ptr<MicrotaskQueue> MicrotaskQueue::New(Isolate* isolate) {
41  DCHECK_NOT_NULL(isolate->default_microtask_queue());
42 
43  std::unique_ptr<MicrotaskQueue> microtask_queue(new MicrotaskQueue);
44 
45  // Insert the new instance to the next of last MicrotaskQueue instance.
46  MicrotaskQueue* last = isolate->default_microtask_queue()->prev_;
47  microtask_queue->next_ = last->next_;
48  microtask_queue->prev_ = last;
49  last->next_->prev_ = microtask_queue.get();
50  last->next_ = microtask_queue.get();
51 
52  return microtask_queue;
53 }
54 
55 MicrotaskQueue::MicrotaskQueue() = default;
56 
57 MicrotaskQueue::~MicrotaskQueue() {
58  if (next_ != this) {
59  DCHECK_NE(prev_, this);
60  next_->prev_ = prev_;
61  prev_->next_ = next_;
62  }
63  delete[] ring_buffer_;
64 }
65 
66 // static
67 Object* MicrotaskQueue::CallEnqueueMicrotask(Isolate* isolate,
68  intptr_t microtask_queue_pointer,
69  Microtask* microtask) {
70  reinterpret_cast<MicrotaskQueue*>(microtask_queue_pointer)
71  ->EnqueueMicrotask(microtask);
72  return ReadOnlyRoots(isolate).undefined_value();
73 }
74 
75 void MicrotaskQueue::EnqueueMicrotask(Microtask* microtask) {
76  if (size_ == capacity_) {
77  // Keep the capacity of |ring_buffer_| power of 2, so that the JIT
78  // implementation can calculate the modulo easily.
79  intptr_t new_capacity = std::max(kMinimumCapacity, capacity_ << 1);
80  ResizeBuffer(new_capacity);
81  }
82 
83  DCHECK_LT(size_, capacity_);
84  ring_buffer_[(start_ + size_) % capacity_] = microtask;
85  ++size_;
86 }
87 
88 int MicrotaskQueue::RunMicrotasks(Isolate* isolate) {
89  HandleScope scope(isolate);
90  MaybeHandle<Object> maybe_exception;
91 
92  // TODO(tzik): Execution::RunMicrotasks() runs default_microtask_queue.
93  // Give it as a parameter to support non-default MicrotaskQueue.
94  DCHECK_EQ(this, isolate->default_microtask_queue());
95  MaybeHandle<Object> maybe_result = Execution::RunMicrotasks(
96  isolate, Execution::MessageHandling::kReport, &maybe_exception);
97 
98  // If execution is terminating, clean up and propagate that to the caller.
99  if (maybe_result.is_null() && maybe_exception.is_null()) {
100  delete[] ring_buffer_;
101  ring_buffer_ = nullptr;
102  capacity_ = 0;
103  size_ = 0;
104  start_ = 0;
105  return -1;
106  }
107 
108  // TODO(tzik): Return the number of microtasks run in this round.
109  return 0;
110 }
111 
112 void MicrotaskQueue::IterateMicrotasks(RootVisitor* visitor) {
113  if (size_) {
114  // Iterate pending Microtasks as root objects to avoid the write barrier for
115  // all single Microtask. If this hurts the GC performance, use a FixedArray.
116  visitor->VisitRootPointers(
117  Root::kStrongRoots, nullptr, ObjectSlot(ring_buffer_ + start_),
118  ObjectSlot(ring_buffer_ + std::min(start_ + size_, capacity_)));
119  visitor->VisitRootPointers(
120  Root::kStrongRoots, nullptr, ObjectSlot(ring_buffer_),
121  ObjectSlot(ring_buffer_ + std::max(start_ + size_ - capacity_,
122  static_cast<intptr_t>(0))));
123  }
124 
125  if (capacity_ <= kMinimumCapacity) {
126  return;
127  }
128 
129  intptr_t new_capacity = capacity_;
130  while (new_capacity > 2 * size_) {
131  new_capacity >>= 1;
132  }
133  new_capacity = std::max(new_capacity, kMinimumCapacity);
134  if (new_capacity < capacity_) {
135  ResizeBuffer(new_capacity);
136  }
137 }
138 
139 void MicrotaskQueue::ResizeBuffer(intptr_t new_capacity) {
140  DCHECK_LE(size_, new_capacity);
141  Object** new_ring_buffer = new Object*[new_capacity];
142  for (intptr_t i = 0; i < size_; ++i) {
143  new_ring_buffer[i] = ring_buffer_[(start_ + i) % capacity_];
144  }
145 
146  delete[] ring_buffer_;
147  ring_buffer_ = new_ring_buffer;
148  capacity_ = new_capacity;
149  start_ = 0;
150 }
151 
152 } // namespace internal
153 } // namespace v8
Definition: libplatform.h:13