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/1417315 Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Taiju Tsuiki <tzik@chromium.org> Cr-Commit-Position: refs/heads/master@{#58901}
This commit is contained in:
parent
2bb5b40f75
commit
eebdb0f54d
@ -258,13 +258,6 @@ V8_WARN_UNUSED_RESULT MaybeHandle<Object> Invoke(Isolate* isolate,
|
||||
Handle<Code> code =
|
||||
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
|
||||
// allocation of handles without explicit handle scopes.
|
||||
SaveContext save(isolate);
|
||||
|
@ -36,9 +36,27 @@ class MicrotaskQueueTest : public TestWithNativeContext {
|
||||
return factory()->NewCallbackTask(runner, data);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
isolate()->default_microtask_queue()->RunMicrotasks(isolate());
|
||||
void SetUp() override {
|
||||
microtask_queue_ = MicrotaskQueue::New(isolate());
|
||||
native_context()->set_microtask_queue(microtask_queue());
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
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 {
|
||||
@ -61,61 +79,57 @@ class RecordingVisitor : public RootVisitor {
|
||||
|
||||
// Sanity check. Ensure a microtask is stored in a queue and run.
|
||||
TEST_F(MicrotaskQueueTest, EnqueueAndRun) {
|
||||
MicrotaskQueue* microtask_queue = isolate()->default_microtask_queue();
|
||||
ASSERT_TRUE(microtask_queue);
|
||||
|
||||
bool ran = false;
|
||||
EXPECT_EQ(0, microtask_queue->capacity());
|
||||
EXPECT_EQ(0, microtask_queue->size());
|
||||
microtask_queue->EnqueueMicrotask(*NewMicrotask([&ran] {
|
||||
EXPECT_EQ(0, microtask_queue()->capacity());
|
||||
EXPECT_EQ(0, microtask_queue()->size());
|
||||
microtask_queue()->EnqueueMicrotask(*NewMicrotask([&ran] {
|
||||
EXPECT_FALSE(ran);
|
||||
ran = true;
|
||||
}));
|
||||
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue->capacity());
|
||||
EXPECT_EQ(1, microtask_queue->size());
|
||||
microtask_queue->RunMicrotasks(isolate());
|
||||
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity());
|
||||
EXPECT_EQ(1, microtask_queue()->size());
|
||||
microtask_queue()->RunMicrotasks(isolate());
|
||||
EXPECT_TRUE(ran);
|
||||
EXPECT_EQ(0, microtask_queue->size());
|
||||
EXPECT_EQ(0, microtask_queue()->size());
|
||||
}
|
||||
|
||||
// Check for a buffer growth.
|
||||
TEST_F(MicrotaskQueueTest, BufferGrowth) {
|
||||
MicrotaskQueue* microtask_queue = isolate()->default_microtask_queue();
|
||||
ASSERT_TRUE(microtask_queue);
|
||||
|
||||
int count = 0;
|
||||
|
||||
// Enqueue and flush the queue first to have non-zero |start_|.
|
||||
microtask_queue->EnqueueMicrotask(
|
||||
microtask_queue()->EnqueueMicrotask(
|
||||
*NewMicrotask([&count] { EXPECT_EQ(0, count++); }));
|
||||
microtask_queue->RunMicrotasks(isolate());
|
||||
microtask_queue()->RunMicrotasks(isolate());
|
||||
|
||||
EXPECT_LT(0, microtask_queue->capacity());
|
||||
EXPECT_EQ(0, microtask_queue->size());
|
||||
EXPECT_EQ(1, microtask_queue->start());
|
||||
EXPECT_LT(0, microtask_queue()->capacity());
|
||||
EXPECT_EQ(0, microtask_queue()->size());
|
||||
EXPECT_EQ(1, microtask_queue()->start());
|
||||
|
||||
// Fill the queue with Microtasks.
|
||||
for (int i = 1; i <= MicrotaskQueue::kMinimumCapacity; ++i) {
|
||||
microtask_queue->EnqueueMicrotask(
|
||||
microtask_queue()->EnqueueMicrotask(
|
||||
*NewMicrotask([&count, i] { EXPECT_EQ(i, count++); }));
|
||||
}
|
||||
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue->capacity());
|
||||
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue->size());
|
||||
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity());
|
||||
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity, microtask_queue()->size());
|
||||
|
||||
// Add another to grow the ring buffer.
|
||||
microtask_queue->EnqueueMicrotask(*NewMicrotask(
|
||||
microtask_queue()->EnqueueMicrotask(*NewMicrotask(
|
||||
[&] { EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, count++); }));
|
||||
|
||||
EXPECT_LT(MicrotaskQueue::kMinimumCapacity, microtask_queue->capacity());
|
||||
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, microtask_queue->size());
|
||||
EXPECT_LT(MicrotaskQueue::kMinimumCapacity, microtask_queue()->capacity());
|
||||
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, microtask_queue()->size());
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// MicrotaskQueue instances form a doubly linked list.
|
||||
TEST_F(MicrotaskQueueTest, InstanceChain) {
|
||||
ClearTestMicrotaskQueue();
|
||||
|
||||
MicrotaskQueue* default_mtq = isolate()->default_microtask_queue();
|
||||
ASSERT_TRUE(default_mtq);
|
||||
EXPECT_EQ(default_mtq, default_mtq->next());
|
||||
@ -145,26 +159,23 @@ TEST_F(MicrotaskQueueTest, InstanceChain) {
|
||||
// Pending Microtasks in MicrotaskQueues are strong roots. Ensure they are
|
||||
// visited exactly once.
|
||||
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.
|
||||
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;
|
||||
for (int i = 0; i < MicrotaskQueue::kMinimumCapacity / 2 + 1; ++i) {
|
||||
Handle<Microtask> microtask = NewMicrotask([] {});
|
||||
expected.push_back(*microtask);
|
||||
microtask_queue->EnqueueMicrotask(*microtask);
|
||||
microtask_queue()->EnqueueMicrotask(*microtask);
|
||||
}
|
||||
EXPECT_GT(microtask_queue->start() + microtask_queue->size(),
|
||||
microtask_queue->capacity());
|
||||
EXPECT_GT(microtask_queue()->start() + microtask_queue()->size(),
|
||||
microtask_queue()->capacity());
|
||||
|
||||
RecordingVisitor visitor;
|
||||
microtask_queue->IterateMicrotasks(&visitor);
|
||||
microtask_queue()->IterateMicrotasks(&visitor);
|
||||
|
||||
std::vector<Object> actual = visitor.visited();
|
||||
std::sort(expected.begin(), expected.end());
|
||||
|
@ -222,7 +222,9 @@ class WithInternalIsolateMixin : public TMixin {
|
||||
Factory* factory() const { return isolate()->factory(); }
|
||||
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>
|
||||
Handle<T> RunJS(const char* source) {
|
||||
|
Loading…
Reference in New Issue
Block a user