Commit 836773c0 authored by tzik's avatar tzik Committed by Commit Bot

Implement v8::internal::MicrotaskQueue::EnqueueMicrotask

This adds `queue` and `pending_microtask_count` as members of
v8::internal::MicrotaskQueue, and implements its EnqueueMicrotask.
The implementation itself is similar to Isolate::EnqueueMicrotask.

Bug: v8:8124
Change-Id: Idb5c50b2add96b72cbe9e36aeec7cb568072f0cb
Reviewed-on: https://chromium-review.googlesource.com/1205430
Commit-Queue: Taiju Tsuiki <tzik@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#55884}
parent 48c129ca
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "src/objects/js-regexp-inl.h" #include "src/objects/js-regexp-inl.h"
#include "src/objects/literal-objects-inl.h" #include "src/objects/literal-objects-inl.h"
#include "src/objects/microtask-inl.h" #include "src/objects/microtask-inl.h"
#include "src/objects/microtask-queue-inl.h"
#include "src/objects/module-inl.h" #include "src/objects/module-inl.h"
#include "src/objects/promise-inl.h" #include "src/objects/promise-inl.h"
#include "src/objects/scope-info.h" #include "src/objects/scope-info.h"
...@@ -1621,6 +1622,16 @@ Handle<PromiseResolveThenableJobTask> Factory::NewPromiseResolveThenableJobTask( ...@@ -1621,6 +1622,16 @@ Handle<PromiseResolveThenableJobTask> Factory::NewPromiseResolveThenableJobTask(
return microtask; return microtask;
} }
Handle<MicrotaskQueue> Factory::NewMicrotaskQueue() {
// MicrotaskQueue should be TENURED, as it outlives Context, and is mostly
// as long-living as Context is.
Handle<MicrotaskQueue> microtask_queue =
Handle<MicrotaskQueue>::cast(NewStruct(MICROTASK_QUEUE_TYPE, TENURED));
microtask_queue->set_queue(*empty_fixed_array());
microtask_queue->set_pending_microtask_count(0);
return microtask_queue;
}
Handle<Foreign> Factory::NewForeign(Address addr, PretenureFlag pretenure) { Handle<Foreign> Factory::NewForeign(Address addr, PretenureFlag pretenure) {
// Statically ensure that it is safe to allocate foreigns in paged spaces. // Statically ensure that it is safe to allocate foreigns in paged spaces.
STATIC_ASSERT(Foreign::kSize <= kMaxRegularHeapObjectSize); STATIC_ASSERT(Foreign::kSize <= kMaxRegularHeapObjectSize);
......
...@@ -439,6 +439,8 @@ class V8_EXPORT_PRIVATE Factory { ...@@ -439,6 +439,8 @@ class V8_EXPORT_PRIVATE Factory {
Handle<JSPromise> promise_to_resolve, Handle<JSReceiver> then, Handle<JSPromise> promise_to_resolve, Handle<JSReceiver> then,
Handle<JSReceiver> thenable, Handle<Context> context); Handle<JSReceiver> thenable, Handle<Context> context);
Handle<MicrotaskQueue> NewMicrotaskQueue();
// Foreign objects are pretenured when allocated by the bootstrapper. // Foreign objects are pretenured when allocated by the bootstrapper.
Handle<Foreign> NewForeign(Address addr, Handle<Foreign> NewForeign(Address addr,
PretenureFlag pretenure = NOT_TENURED); PretenureFlag pretenure = NOT_TENURED);
......
...@@ -1284,7 +1284,12 @@ void PromiseReactionJobTask::PromiseReactionJobTaskVerify(Isolate* isolate) { ...@@ -1284,7 +1284,12 @@ void PromiseReactionJobTask::PromiseReactionJobTaskVerify(Isolate* isolate) {
promise_or_capability()->IsPromiseCapability()); promise_or_capability()->IsPromiseCapability());
} }
void MicrotaskQueue::MicrotaskQueueVerify(Isolate* isolate) { UNIMPLEMENTED(); } void MicrotaskQueue::MicrotaskQueueVerify(Isolate* isolate) {
CHECK(IsMicrotaskQueue());
VerifyHeapPointer(isolate, queue());
VerifySmiField(kPendingMicrotaskCountOffset);
CHECK_LE(pending_microtask_count(), queue()->length());
}
void PromiseFulfillReactionJobTask::PromiseFulfillReactionJobTaskVerify( void PromiseFulfillReactionJobTask::PromiseFulfillReactionJobTaskVerify(
Isolate* isolate) { Isolate* isolate) {
......
...@@ -2198,7 +2198,10 @@ void UncompiledDataWithPreParsedScope::UncompiledDataWithPreParsedScopePrint( ...@@ -2198,7 +2198,10 @@ void UncompiledDataWithPreParsedScope::UncompiledDataWithPreParsedScopePrint(
} }
void MicrotaskQueue::MicrotaskQueuePrint(std::ostream& os) { // NOLINT void MicrotaskQueue::MicrotaskQueuePrint(std::ostream& os) { // NOLINT
UNIMPLEMENTED(); HeapObject::PrintHeader(os, "MicrotaskQueue");
os << "\n - pending_microtask_count: " << pending_microtask_count();
os << "\n - queue: " << Brief(queue());
os << "\n";
} }
void InterpreterData::InterpreterDataPrint(std::ostream& os) { // NOLINT void InterpreterData::InterpreterDataPrint(std::ostream& os) { // NOLINT
......
...@@ -16,6 +16,9 @@ namespace v8 { ...@@ -16,6 +16,9 @@ namespace v8 {
namespace internal { namespace internal {
CAST_ACCESSOR(MicrotaskQueue) CAST_ACCESSOR(MicrotaskQueue)
ACCESSORS(MicrotaskQueue, queue, FixedArray, kQueueOffset)
SMI_ACCESSORS(MicrotaskQueue, pending_microtask_count,
kPendingMicrotaskCountOffset)
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -10,9 +10,22 @@ namespace v8 { ...@@ -10,9 +10,22 @@ namespace v8 {
namespace internal { namespace internal {
// static // static
void MicrotaskQueue::EnqueueMicrotask(Handle<MicrotaskQueue> microtask_queue, void MicrotaskQueue::EnqueueMicrotask(Isolate* isolate,
Handle<MicrotaskQueue> microtask_queue,
Handle<Microtask> microtask) { Handle<Microtask> microtask) {
UNIMPLEMENTED(); Handle<FixedArray> queue(microtask_queue->queue(), isolate);
int num_tasks = microtask_queue->pending_microtask_count();
DCHECK_LE(num_tasks, queue->length());
if (num_tasks == queue->length()) {
queue = isolate->factory()->CopyFixedArrayAndGrow(
queue, std::max(num_tasks, kMinimumQueueCapacity));
microtask_queue->set_queue(*queue);
}
DCHECK_LE(kMinimumQueueCapacity, queue->length());
DCHECK_LT(num_tasks, queue->length());
DCHECK(queue->get(num_tasks)->IsUndefined(isolate));
queue->set(num_tasks, *microtask);
microtask_queue->set_pending_microtask_count(num_tasks + 1);
} }
// static // static
......
...@@ -14,17 +14,34 @@ ...@@ -14,17 +14,34 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
class MicrotaskQueue : public Struct { class V8_EXPORT_PRIVATE MicrotaskQueue : public Struct {
public: public:
DECL_CAST(MicrotaskQueue) DECL_CAST(MicrotaskQueue)
DECL_VERIFIER(MicrotaskQueue) DECL_VERIFIER(MicrotaskQueue)
DECL_PRINTER(MicrotaskQueue) DECL_PRINTER(MicrotaskQueue)
static void EnqueueMicrotask(Handle<MicrotaskQueue> microtask_queue, // A FixedArray that the queued microtasks are stored.
// The first |pending_microtask_count| slots contains Microtask instance
// for each, and followings are undefined_value if any.
DECL_ACCESSORS(queue, FixedArray)
// The number of microtasks queued in |queue|. This must be less or equal to
// the length of |queue|.
DECL_INT_ACCESSORS(pending_microtask_count)
// Enqueues |microtask| to |microtask_queue|.
static void EnqueueMicrotask(Isolate* isolate,
Handle<MicrotaskQueue> microtask_queue,
Handle<Microtask> microtask); Handle<Microtask> microtask);
// Runs all enqueued microtasks.
static void RunMicrotasks(Handle<MicrotaskQueue> microtask_queue); static void RunMicrotasks(Handle<MicrotaskQueue> microtask_queue);
static const int kSize = HeapObject::kHeaderSize; static constexpr int kMinimumQueueCapacity = 8;
static const int kQueueOffset = HeapObject::kHeaderSize;
static const int kPendingMicrotaskCountOffset = kQueueOffset + kPointerSize;
static const int kSize = kPendingMicrotaskCountOffset + kPointerSize;
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(MicrotaskQueue); DISALLOW_IMPLICIT_CONSTRUCTORS(MicrotaskQueue);
......
...@@ -183,6 +183,7 @@ v8_source_set("unittests_sources") { ...@@ -183,6 +183,7 @@ v8_source_set("unittests_sources") {
"libplatform/worker-thread-unittest.cc", "libplatform/worker-thread-unittest.cc",
"locked-queue-unittest.cc", "locked-queue-unittest.cc",
"object-unittest.cc", "object-unittest.cc",
"objects/microtask-queue-unittest.cc",
"parser/ast-value-unittest.cc", "parser/ast-value-unittest.cc",
"parser/preparser-unittest.cc", "parser/preparser-unittest.cc",
"register-configuration-unittest.cc", "register-configuration-unittest.cc",
......
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/objects/microtask-queue.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
void NoopCallback(void*) {}
class MicrotaskQueueTest : public TestWithIsolate {
public:
Handle<Microtask> NewMicrotask() {
MicrotaskCallback callback = &NoopCallback;
void* data = nullptr;
return factory()->NewCallbackTask(
factory()->NewForeign(reinterpret_cast<Address>(callback)),
factory()->NewForeign(reinterpret_cast<Address>(data)));
}
};
TEST_F(MicrotaskQueueTest, EnqueueMicrotask) {
Handle<MicrotaskQueue> microtask_queue = factory()->NewMicrotaskQueue();
Handle<Microtask> microtask = NewMicrotask();
EXPECT_EQ(0, microtask_queue->pending_microtask_count());
MicrotaskQueue::EnqueueMicrotask(isolate(), microtask_queue, microtask);
EXPECT_EQ(1, microtask_queue->pending_microtask_count());
ASSERT_LE(1, microtask_queue->queue()->length());
EXPECT_EQ(*microtask, microtask_queue->queue()->get(0));
std::vector<Handle<Microtask>> microtasks;
microtasks.push_back(microtask);
// Queue microtasks until the reallocation.
int queue_capacity = microtask_queue->queue()->length();
for (int i = 0; i < queue_capacity; ++i) {
microtask = NewMicrotask();
MicrotaskQueue::EnqueueMicrotask(isolate(), microtask_queue, microtask);
microtasks.push_back(microtask);
}
int num_tasks = static_cast<int>(microtasks.size());
EXPECT_EQ(num_tasks, microtask_queue->pending_microtask_count());
ASSERT_LE(num_tasks, microtask_queue->queue()->length());
for (int i = 0; i < num_tasks; ++i) {
EXPECT_EQ(*microtasks[i], microtask_queue->queue()->get(i));
}
}
} // namespace internal
} // namespace v8
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