Commit eebdb0f5 authored by tzik's avatar tzik Committed by Commit Bot

Use local MicrotaskQueue in unittests

MicrotaskQueueTest uses Isolate's default_microtask_queue for testing,
however the instance is shared between test cases, and causes flaky
failure of MicrotaskQueueTest.BufferGrowth.

This CL adds a MicrotaskQueue instance for each test fixture, so that
each test cases use separate ones.

Also, this CL removes the DCHECK that denies non-default MicrotaskQueue
to run, which is unneeded after https://crrev.com/c/1369906.

Bug: v8:8124
Change-Id: I4ff236c327bf0be14f582b3ca8c802fd72661b42
Reviewed-on: https://chromium-review.googlesource.com/c/1417315Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Commit-Queue: Taiju Tsuiki <tzik@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58901}
parent 2bb5b40f
...@@ -258,13 +258,6 @@ V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate, ...@@ -258,13 +258,6 @@ V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
Handle<Code> code = Handle<Code> code =
JSEntry(isolate, params.execution_target, params.is_construct); JSEntry(isolate, params.execution_target, params.is_construct);
{ {
// Non-default MicrotaskQueue is currently unsupported.
// TODO(tzik): Remove this DCHECK once the entry function is ready to handle
// the microtask_queue parameter.
DCHECK_IMPLIES(
params.execution_target == Execution::Target::kRunMicrotasks,
params.microtask_queue == isolate->default_microtask_queue());
// Save and restore context around invocation and block the // Save and restore context around invocation and block the
// allocation of handles without explicit handle scopes. // allocation of handles without explicit handle scopes.
SaveContext save(isolate); SaveContext save(isolate);
......
...@@ -36,9 +36,27 @@ class MicrotaskQueueTest : public TestWithNativeContext { ...@@ -36,9 +36,27 @@ class MicrotaskQueueTest : public TestWithNativeContext {
return factory()->NewCallbackTask(runner, data); return factory()->NewCallbackTask(runner, data);
} }
void SetUp() override {
microtask_queue_ = MicrotaskQueue::New(isolate());
native_context()->set_microtask_queue(microtask_queue());
}
void TearDown() override { void TearDown() override {
isolate()->default_microtask_queue()->RunMicrotasks(isolate()); if (microtask_queue()) {
microtask_queue()->RunMicrotasks(isolate());
context()->DetachGlobal();
}
}
MicrotaskQueue* microtask_queue() const { return microtask_queue_.get(); }
void ClearTestMicrotaskQueue() {
context()->DetachGlobal();
microtask_queue_ = nullptr;
} }
private:
std::unique_ptr<MicrotaskQueue> microtask_queue_;
}; };
class RecordingVisitor : public RootVisitor { class RecordingVisitor : public RootVisitor {
...@@ -61,61 +79,57 @@ class RecordingVisitor : public RootVisitor { ...@@ -61,61 +79,57 @@ class RecordingVisitor : public RootVisitor {
// Sanity check. Ensure a microtask is stored in a queue and run. // Sanity check. Ensure a microtask is stored in a queue and run.
TEST_F(MicrotaskQueueTest, EnqueueAndRun) { TEST_F(MicrotaskQueueTest, EnqueueAndRun) {
MicrotaskQueue* microtask_queue = isolate()->default_microtask_queue();
ASSERT_TRUE(microtask_queue);
bool ran = false; bool ran = false;
EXPECT_EQ(0, microtask_queue->capacity()); EXPECT_EQ(0, microtask_queue()->capacity());
EXPECT_EQ(0, microtask_queue->size()); EXPECT_EQ(0, microtask_queue()->size());
microtask_queue->EnqueueMicrotask(*NewMicrotask([&ran] { microtask_queue()->EnqueueMicrotask(*NewMicrotask([&ran] {
EXPECT_FALSE(ran); EXPECT_FALSE(ran);
ran = true; ran = true;
})); }));
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue->capacity()); EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity());
EXPECT_EQ(1, microtask_queue->size()); EXPECT_EQ(1, microtask_queue()->size());
microtask_queue->RunMicrotasks(isolate()); microtask_queue()->RunMicrotasks(isolate());
EXPECT_TRUE(ran); EXPECT_TRUE(ran);
EXPECT_EQ(0, microtask_queue->size()); EXPECT_EQ(0, microtask_queue()->size());
} }
// Check for a buffer growth. // Check for a buffer growth.
TEST_F(MicrotaskQueueTest, BufferGrowth) { TEST_F(MicrotaskQueueTest, BufferGrowth) {
MicrotaskQueue* microtask_queue = isolate()->default_microtask_queue();
ASSERT_TRUE(microtask_queue);
int count = 0; int count = 0;
// Enqueue and flush the queue first to have non-zero |start_|. // Enqueue and flush the queue first to have non-zero |start_|.
microtask_queue->EnqueueMicrotask( microtask_queue()->EnqueueMicrotask(
*NewMicrotask([&count] { EXPECT_EQ(0, count++); })); *NewMicrotask([&count] { EXPECT_EQ(0, count++); }));
microtask_queue->RunMicrotasks(isolate()); microtask_queue()->RunMicrotasks(isolate());
EXPECT_LT(0, microtask_queue->capacity()); EXPECT_LT(0, microtask_queue()->capacity());
EXPECT_EQ(0, microtask_queue->size()); EXPECT_EQ(0, microtask_queue()->size());
EXPECT_EQ(1, microtask_queue->start()); EXPECT_EQ(1, microtask_queue()->start());
// Fill the queue with Microtasks. // Fill the queue with Microtasks.
for (int i = 1; i <= MicrotaskQueue::kMinimumCapacity; ++i) { for (int i = 1; i <= MicrotaskQueue::kMinimumCapacity; ++i) {
microtask_queue->EnqueueMicrotask( microtask_queue()->EnqueueMicrotask(
*NewMicrotask([&count, i] { EXPECT_EQ(i, count++); })); *NewMicrotask([&count, i] { EXPECT_EQ(i, count++); }));
} }
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue->capacity()); EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity());
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue->size()); EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->size());
// Add another to grow the ring buffer. // Add another to grow the ring buffer.
microtask_queue->EnqueueMicrotask(*NewMicrotask( microtask_queue()->EnqueueMicrotask(*NewMicrotask(
[&] { EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, count++); })); [&] { EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, count++); }));
EXPECT_LT(MicrotaskQueue::kMinimumCapacity, microtask_queue->capacity()); EXPECT_LT(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity());
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, microtask_queue->size()); EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, microtask_queue()->size());
// Run all pending Microtasks to ensure they run in the proper order. // Run all pending Microtasks to ensure they run in the proper order.
microtask_queue->RunMicrotasks(isolate()); microtask_queue()->RunMicrotasks(isolate());
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 2, count); EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 2, count);
} }
// MicrotaskQueue instances form a doubly linked list. // MicrotaskQueue instances form a doubly linked list.
TEST_F(MicrotaskQueueTest, InstanceChain) { TEST_F(MicrotaskQueueTest, InstanceChain) {
ClearTestMicrotaskQueue();
MicrotaskQueue* default_mtq = isolate()->default_microtask_queue(); MicrotaskQueue* default_mtq = isolate()->default_microtask_queue();
ASSERT_TRUE(default_mtq); ASSERT_TRUE(default_mtq);
EXPECT_EQ(default_mtq, default_mtq->next()); EXPECT_EQ(default_mtq, default_mtq->next());
...@@ -145,26 +159,23 @@ TEST_F(MicrotaskQueueTest, InstanceChain) { ...@@ -145,26 +159,23 @@ TEST_F(MicrotaskQueueTest, InstanceChain) {
// Pending Microtasks in MicrotaskQueues are strong roots. Ensure they are // Pending Microtasks in MicrotaskQueues are strong roots. Ensure they are
// visited exactly once. // visited exactly once.
TEST_F(MicrotaskQueueTest, VisitRoot) { TEST_F(MicrotaskQueueTest, VisitRoot) {
MicrotaskQueue* microtask_queue = isolate()->default_microtask_queue();
ASSERT_TRUE(microtask_queue);
// Ensure that the ring buffer has separate in-use region. // Ensure that the ring buffer has separate in-use region.
for (int i = 0; i < MicrotaskQueue::kMinimumCapacity / 2 + 1; ++i) { for (int i = 0; i < MicrotaskQueue::kMinimumCapacity / 2 + 1; ++i) {
microtask_queue->EnqueueMicrotask(*NewMicrotask([] {})); microtask_queue()->EnqueueMicrotask(*NewMicrotask([] {}));
} }
microtask_queue->RunMicrotasks(isolate()); microtask_queue()->RunMicrotasks(isolate());
std::vector<Object> expected; std::vector<Object> expected;
for (int i = 0; i < MicrotaskQueue::kMinimumCapacity / 2 + 1; ++i) { for (int i = 0; i < MicrotaskQueue::kMinimumCapacity / 2 + 1; ++i) {
Handle<Microtask> microtask = NewMicrotask([] {}); Handle<Microtask> microtask = NewMicrotask([] {});
expected.push_back(*microtask); expected.push_back(*microtask);
microtask_queue->EnqueueMicrotask(*microtask); microtask_queue()->EnqueueMicrotask(*microtask);
} }
EXPECT_GT(microtask_queue->start() + microtask_queue->size(), EXPECT_GT(microtask_queue()->start() + microtask_queue()->size(),
microtask_queue->capacity()); microtask_queue()->capacity());
RecordingVisitor visitor; RecordingVisitor visitor;
microtask_queue->IterateMicrotasks(&visitor); microtask_queue()->IterateMicrotasks(&visitor);
std::vector<Object> actual = visitor.visited(); std::vector<Object> actual = visitor.visited();
std::sort(expected.begin(), expected.end()); std::sort(expected.begin(), expected.end());
......
...@@ -222,7 +222,9 @@ class WithInternalIsolateMixin : public TMixin { ...@@ -222,7 +222,9 @@ class WithInternalIsolateMixin : public TMixin {
Factory* factory() const { return isolate()->factory(); } Factory* factory() const { return isolate()->factory(); }
Isolate* isolate() const { return TMixin::i_isolate(); } Isolate* isolate() const { return TMixin::i_isolate(); }
Handle<Context> native_context() const { return isolate()->native_context(); } Handle<NativeContext> native_context() const {
return isolate()->native_context();
}
template <typename T = Object> template <typename T = Object>
Handle<T> RunJS(const char* source) { Handle<T> RunJS(const char* source) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment