LCOV - code coverage report
Current view: top level - test/unittests - microtask-queue-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 90 91 98.9 %
Date: 2019-01-20 Functions: 26 33 78.8 %

          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             : #include "src/microtask-queue.h"
       6             : 
       7             : #include <algorithm>
       8             : #include <functional>
       9             : #include <memory>
      10             : #include <vector>
      11             : 
      12             : #include "src/heap/factory.h"
      13             : #include "src/objects/foreign.h"
      14             : #include "src/visitors.h"
      15             : #include "test/unittests/test-utils.h"
      16             : #include "testing/gtest/include/gtest/gtest.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : 
      21             : using Closure = std::function<void()>;
      22             : 
      23          21 : void RunStdFunction(void* data) {
      24             :   std::unique_ptr<Closure> f(static_cast<Closure*>(data));
      25          21 :   (*f)();
      26          21 : }
      27             : 
      28          12 : class MicrotaskQueueTest : public TestWithNativeContext {
      29             :  public:
      30             :   template <typename F>
      31          21 :   Handle<Microtask> NewMicrotask(F&& f) {
      32             :     Handle<Foreign> runner =
      33          42 :         factory()->NewForeign(reinterpret_cast<Address>(&RunStdFunction));
      34             :     Handle<Foreign> data = factory()->NewForeign(
      35          63 :         reinterpret_cast<Address>(new Closure(std::forward<F>(f))));
      36          21 :     return factory()->NewCallbackTask(runner, data);
      37             :   }
      38             : 
      39           4 :   void SetUp() override {
      40           8 :     microtask_queue_ = MicrotaskQueue::New(isolate());
      41             :     native_context()->set_microtask_queue(microtask_queue());
      42           4 :   }
      43             : 
      44           4 :   void TearDown() override {
      45           4 :     if (microtask_queue()) {
      46           3 :       microtask_queue()->RunMicrotasks(isolate());
      47           3 :       context()->DetachGlobal();
      48             :     }
      49           4 :   }
      50             : 
      51             :   MicrotaskQueue* microtask_queue() const { return microtask_queue_.get(); }
      52             : 
      53           1 :   void ClearTestMicrotaskQueue() {
      54           1 :     context()->DetachGlobal();
      55             :     microtask_queue_ = nullptr;
      56           1 :   }
      57             : 
      58             :  private:
      59             :   std::unique_ptr<MicrotaskQueue> microtask_queue_;
      60             : };
      61             : 
      62             : class RecordingVisitor : public RootVisitor {
      63             :  public:
      64           1 :   RecordingVisitor() = default;
      65           1 :   ~RecordingVisitor() override = default;
      66             : 
      67           2 :   void VisitRootPointers(Root root, const char* description,
      68             :                          FullObjectSlot start, FullObjectSlot end) override {
      69           9 :     for (FullObjectSlot current = start; current != end; ++current) {
      70          10 :       visited_.push_back(*current);
      71             :     }
      72           2 :   }
      73             : 
      74             :   const std::vector<Object>& visited() const { return visited_; }
      75             : 
      76             :  private:
      77             :   std::vector<Object> visited_;
      78             : };
      79             : 
      80             : // Sanity check. Ensure a microtask is stored in a queue and run.
      81       15128 : TEST_F(MicrotaskQueueTest, EnqueueAndRun) {
      82           1 :   bool ran = false;
      83           2 :   EXPECT_EQ(0, microtask_queue()->capacity());
      84           2 :   EXPECT_EQ(0, microtask_queue()->size());
      85           1 :   microtask_queue()->EnqueueMicrotask(*NewMicrotask([&ran] {
      86           2 :     EXPECT_FALSE(ran);
      87           1 :     ran = true;
      88           3 :   }));
      89           2 :   EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity());
      90           2 :   EXPECT_EQ(1, microtask_queue()->size());
      91           1 :   microtask_queue()->RunMicrotasks(isolate());
      92           1 :   EXPECT_TRUE(ran);
      93           2 :   EXPECT_EQ(0, microtask_queue()->size());
      94           1 : }
      95             : 
      96             : // Check for a buffer growth.
      97       15128 : TEST_F(MicrotaskQueueTest, BufferGrowth) {
      98           1 :   int count = 0;
      99             : 
     100             :   // Enqueue and flush the queue first to have non-zero |start_|.
     101             :   microtask_queue()->EnqueueMicrotask(
     102           5 :       *NewMicrotask([&count] { EXPECT_EQ(0, count++); }));
     103           1 :   microtask_queue()->RunMicrotasks(isolate());
     104             : 
     105           1 :   EXPECT_LT(0, microtask_queue()->capacity());
     106           2 :   EXPECT_EQ(0, microtask_queue()->size());
     107           2 :   EXPECT_EQ(1, microtask_queue()->start());
     108             : 
     109             :   // Fill the queue with Microtasks.
     110           9 :   for (int i = 1; i <= MicrotaskQueue::kMinimumCapacity; ++i) {
     111             :     microtask_queue()->EnqueueMicrotask(
     112          40 :         *NewMicrotask([&count, i] { EXPECT_EQ(i, count++); }));
     113             :   }
     114           2 :   EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity());
     115           2 :   EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->size());
     116             : 
     117             :   // Add another to grow the ring buffer.
     118             :   microtask_queue()->EnqueueMicrotask(*NewMicrotask(
     119           5 :       [&] { EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, count++); }));
     120             : 
     121           1 :   EXPECT_LT(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity());
     122           2 :   EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, microtask_queue()->size());
     123             : 
     124             :   // Run all pending Microtasks to ensure they run in the proper order.
     125           1 :   microtask_queue()->RunMicrotasks(isolate());
     126           2 :   EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 2, count);
     127           1 : }
     128             : 
     129             : // MicrotaskQueue instances form a doubly linked list.
     130       15128 : TEST_F(MicrotaskQueueTest, InstanceChain) {
     131           1 :   ClearTestMicrotaskQueue();
     132             : 
     133           1 :   MicrotaskQueue* default_mtq = isolate()->default_microtask_queue();
     134           2 :   ASSERT_TRUE(default_mtq);
     135           7 :   EXPECT_EQ(default_mtq, default_mtq->next());
     136           3 :   EXPECT_EQ(default_mtq, default_mtq->prev());
     137             : 
     138             :   // Create two instances, and check their connection.
     139             :   // The list contains all instances in the creation order, and the next of the
     140             :   // last instance is the first instance:
     141             :   //   default_mtq -> mtq1 -> mtq2 -> default_mtq.
     142           1 :   std::unique_ptr<MicrotaskQueue> mtq1 = MicrotaskQueue::New(isolate());
     143           1 :   std::unique_ptr<MicrotaskQueue> mtq2 = MicrotaskQueue::New(isolate());
     144           3 :   EXPECT_EQ(default_mtq->next(), mtq1.get());
     145           3 :   EXPECT_EQ(mtq1->next(), mtq2.get());
     146           2 :   EXPECT_EQ(mtq2->next(), default_mtq);
     147           2 :   EXPECT_EQ(default_mtq, mtq1->prev());
     148           3 :   EXPECT_EQ(mtq1.get(), mtq2->prev());
     149           4 :   EXPECT_EQ(mtq2.get(), default_mtq->prev());
     150             : 
     151             :   // Deleted item should be also removed from the list.
     152             :   mtq1 = nullptr;
     153           3 :   EXPECT_EQ(default_mtq->next(), mtq2.get());
     154           2 :   EXPECT_EQ(mtq2->next(), default_mtq);
     155           2 :   EXPECT_EQ(default_mtq, mtq2->prev());
     156           4 :   EXPECT_EQ(mtq2.get(), default_mtq->prev());
     157             : }
     158             : 
     159             : // Pending Microtasks in MicrotaskQueues are strong roots. Ensure they are
     160             : // visited exactly once.
     161       15128 : TEST_F(MicrotaskQueueTest, VisitRoot) {
     162             :   // Ensure that the ring buffer has separate in-use region.
     163           6 :   for (int i = 0; i < MicrotaskQueue::kMinimumCapacity / 2 + 1; ++i) {
     164          10 :     microtask_queue()->EnqueueMicrotask(*NewMicrotask([] {}));
     165             :   }
     166           1 :   microtask_queue()->RunMicrotasks(isolate());
     167             : 
     168             :   std::vector<Object> expected;
     169           6 :   for (int i = 0; i < MicrotaskQueue::kMinimumCapacity / 2 + 1; ++i) {
     170           5 :     Handle<Microtask> microtask = NewMicrotask([] {});
     171          10 :     expected.push_back(*microtask);
     172           5 :     microtask_queue()->EnqueueMicrotask(*microtask);
     173             :   }
     174           1 :   EXPECT_GT(microtask_queue()->start() + microtask_queue()->size(),
     175           0 :             microtask_queue()->capacity());
     176             : 
     177             :   RecordingVisitor visitor;
     178           1 :   microtask_queue()->IterateMicrotasks(&visitor);
     179             : 
     180           1 :   std::vector<Object> actual = visitor.visited();
     181           1 :   std::sort(expected.begin(), expected.end());
     182           1 :   std::sort(actual.begin(), actual.end());
     183           1 :   EXPECT_EQ(expected, actual);
     184           1 : }
     185             : 
     186             : }  // namespace internal
     187        9075 : }  // namespace v8

Generated by: LCOV version 1.10