Move MicrotaskQueue-related flags to MtQ itself

This CL moves variables that control MicrotaskQueue to MtQ itself.
Namely,
 * is_running_microtasks_ and microtask_completed_callbacks_ from
   v8::internal::Isolate
 * microtasks_depth_, microtasks_suppressions_ and debug_microtask_depth_
   from v8::internal::HandleScopeImplementer.

As the current implementation has these variables one per-Isolate rather
than per-MicrotaskQueue, this is needed to have multiple MicrotaskQueues
for an Isolate.

Bug: v8:8124
Change-Id: Id63075cbfb59cf5b7f45a4184affb206400150da
Reviewed-on: https://chromium-review.googlesource.com/c/1358029
Commit-Queue: Taiju Tsuiki <tzik@chromium.org>
Reviewed-by: Adam Klein <adamk@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58348}
This commit is contained in:
tzik 2018-12-19 16:28:37 +09:00 committed by Commit Bot
parent c6d8c75557
commit f2c2742c50
13 changed files with 146 additions and 120 deletions

View File

@ -49,6 +49,7 @@
#include "src/json-parser.h"
#include "src/json-stringifier.h"
#include "src/messages.h"
#include "src/microtask-queue.h"
#include "src/objects-inl.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/embedder-data-array-inl.h"
@ -251,10 +252,11 @@ class InternalEscapableScope : public v8::EscapableHandleScope {
#ifdef V8_CHECK_MICROTASKS_SCOPES_CONSISTENCY
void CheckMicrotasksScopesConsistency(i::Isolate* isolate) {
auto handle_scope_implementer = isolate->handle_scope_implementer();
auto* microtask_queue = isolate->default_microtask_queue();
if (handle_scope_implementer->microtasks_policy() ==
v8::MicrotasksPolicy::kScoped) {
DCHECK(handle_scope_implementer->GetMicrotasksScopeDepth() ||
!handle_scope_implementer->DebugMicrotasksScopeDepthIsZero());
DCHECK(microtask_queue->GetMicrotasksScopeDepth() ||
!microtask_queue->DebugMicrotasksScopeDepthIsZero());
}
}
#endif
@ -8334,12 +8336,12 @@ Isolate::SuppressMicrotaskExecutionScope::SuppressMicrotaskExecutionScope(
Isolate* isolate)
: isolate_(reinterpret_cast<i::Isolate*>(isolate)) {
isolate_->handle_scope_implementer()->IncrementCallDepth();
isolate_->handle_scope_implementer()->IncrementMicrotasksSuppressions();
isolate_->default_microtask_queue()->IncrementMicrotasksSuppressions();
}
Isolate::SuppressMicrotaskExecutionScope::~SuppressMicrotaskExecutionScope() {
isolate_->handle_scope_implementer()->DecrementMicrotasksSuppressions();
isolate_->default_microtask_queue()->DecrementMicrotasksSuppressions();
isolate_->handle_scope_implementer()->DecrementCallDepth();
}
@ -8542,7 +8544,7 @@ void Isolate::EnqueueMicrotask(Local<Function> function) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
i::Handle<i::CallableTask> microtask = isolate->factory()->NewCallableTask(
Utils::OpenHandle(*function), isolate->native_context());
isolate->EnqueueMicrotask(microtask);
isolate->default_microtask_queue()->EnqueueMicrotask(*microtask);
}
void Isolate::EnqueueMicrotask(MicrotaskCallback callback, void* data) {
@ -8551,7 +8553,7 @@ void Isolate::EnqueueMicrotask(MicrotaskCallback callback, void* data) {
i::Handle<i::CallbackTask> microtask = isolate->factory()->NewCallbackTask(
isolate->factory()->NewForeign(reinterpret_cast<i::Address>(callback)),
isolate->factory()->NewForeign(reinterpret_cast<i::Address>(data)));
isolate->EnqueueMicrotask(microtask);
isolate->default_microtask_queue()->EnqueueMicrotask(*microtask);
}
@ -8572,14 +8574,15 @@ void Isolate::AddMicrotasksCompletedCallback(
MicrotasksCompletedCallback callback) {
DCHECK(callback);
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->AddMicrotasksCompletedCallback(callback);
isolate->default_microtask_queue()->AddMicrotasksCompletedCallback(callback);
}
void Isolate::RemoveMicrotasksCompletedCallback(
MicrotasksCompletedCallback callback) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->RemoveMicrotasksCompletedCallback(callback);
isolate->default_microtask_queue()->RemoveMicrotasksCompletedCallback(
callback);
}
@ -8877,34 +8880,35 @@ void Isolate::SetAllowAtomicsWait(bool allow) {
MicrotasksScope::MicrotasksScope(Isolate* isolate, MicrotasksScope::Type type)
: isolate_(reinterpret_cast<i::Isolate*>(isolate)),
run_(type == MicrotasksScope::kRunMicrotasks) {
auto handle_scope_implementer = isolate_->handle_scope_implementer();
if (run_) handle_scope_implementer->IncrementMicrotasksScopeDepth();
auto* microtask_queue = isolate_->default_microtask_queue();
if (run_) microtask_queue->IncrementMicrotasksScopeDepth();
#ifdef DEBUG
if (!run_) handle_scope_implementer->IncrementDebugMicrotasksScopeDepth();
if (!run_) microtask_queue->IncrementDebugMicrotasksScopeDepth();
#endif
}
MicrotasksScope::~MicrotasksScope() {
auto handle_scope_implementer = isolate_->handle_scope_implementer();
auto* microtask_queue = isolate_->default_microtask_queue();
if (run_) {
handle_scope_implementer->DecrementMicrotasksScopeDepth();
microtask_queue->DecrementMicrotasksScopeDepth();
if (MicrotasksPolicy::kScoped ==
handle_scope_implementer->microtasks_policy()) {
PerformCheckpoint(reinterpret_cast<Isolate*>(isolate_));
}
}
#ifdef DEBUG
if (!run_) handle_scope_implementer->DecrementDebugMicrotasksScopeDepth();
if (!run_) microtask_queue->DecrementDebugMicrotasksScopeDepth();
#endif
}
void MicrotasksScope::PerformCheckpoint(Isolate* v8Isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8Isolate);
auto handle_scope_implementer = isolate->handle_scope_implementer();
if (!handle_scope_implementer->GetMicrotasksScopeDepth() &&
!handle_scope_implementer->HasMicrotasksSuppressions()) {
auto* microtask_queue = isolate->default_microtask_queue();
if (!microtask_queue->GetMicrotasksScopeDepth() &&
!microtask_queue->HasMicrotasksSuppressions()) {
isolate->RunMicrotasks();
}
}
@ -8912,12 +8916,12 @@ void MicrotasksScope::PerformCheckpoint(Isolate* v8Isolate) {
int MicrotasksScope::GetCurrentDepth(Isolate* v8Isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8Isolate);
return isolate->handle_scope_implementer()->GetMicrotasksScopeDepth();
return isolate->default_microtask_queue()->GetMicrotasksScopeDepth();
}
bool MicrotasksScope::IsRunningMicrotasks(Isolate* v8Isolate) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8Isolate);
return isolate->IsRunningMicrotasks();
return isolate->default_microtask_queue()->IsRunningMicrotasks();
}
String::Utf8Value::Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> obj)

View File

@ -355,11 +355,6 @@ class HandleScopeImplementer {
: isolate_(isolate),
spare_(nullptr),
call_depth_(0),
microtasks_depth_(0),
microtasks_suppressions_(0),
#ifdef DEBUG
debug_microtasks_depth_(0),
#endif
microtasks_policy_(v8::MicrotasksPolicy::kAuto),
last_handle_before_deferred_block_(nullptr) {
}
@ -386,31 +381,6 @@ class HandleScopeImplementer {
inline void DecrementCallDepth() {call_depth_--;}
inline bool CallDepthIsZero() { return call_depth_ == 0; }
// Microtasks scope depth represents nested scopes controlling microtasks
// invocation, which happens when depth reaches zero.
inline void IncrementMicrotasksScopeDepth() {microtasks_depth_++;}
inline void DecrementMicrotasksScopeDepth() {microtasks_depth_--;}
inline int GetMicrotasksScopeDepth() { return microtasks_depth_; }
// Possibly nested microtasks suppression scopes prevent microtasks
// from running.
inline void IncrementMicrotasksSuppressions() {microtasks_suppressions_++;}
inline void DecrementMicrotasksSuppressions() {microtasks_suppressions_--;}
inline bool HasMicrotasksSuppressions() { return !!microtasks_suppressions_; }
#ifdef DEBUG
// In debug we check that calls not intended to invoke microtasks are
// still correctly wrapped with microtask scopes.
inline void IncrementDebugMicrotasksScopeDepth() {debug_microtasks_depth_++;}
inline void DecrementDebugMicrotasksScopeDepth() {debug_microtasks_depth_--;}
inline bool DebugMicrotasksScopeDepthIsZero() {
return debug_microtasks_depth_ == 0;
}
#endif
inline void set_microtasks_policy(v8::MicrotasksPolicy policy);
inline v8::MicrotasksPolicy microtasks_policy() const;
inline void EnterContext(Context context);
inline void LeaveContext();
inline bool LastEnteredContextWas(Context context);
@ -418,6 +388,9 @@ class HandleScopeImplementer {
inline void EnterMicrotaskContext(Context context);
inline void set_microtasks_policy(v8::MicrotasksPolicy policy);
inline v8::MicrotasksPolicy microtasks_policy() const;
// Returns the last entered context or an empty handle if no
// contexts have been entered.
inline Handle<Context> LastEnteredContext();
@ -485,12 +458,9 @@ class HandleScopeImplementer {
DetachableVector<Context> saved_contexts_;
Address* spare_;
int call_depth_;
int microtasks_depth_;
int microtasks_suppressions_;
#ifdef DEBUG
int debug_microtasks_depth_;
#endif
v8::MicrotasksPolicy microtasks_policy_;
Address* last_handle_before_deferred_block_;
// This is only used for threading support.
HandleScopeData handle_scope_data_;

View File

@ -953,7 +953,7 @@ void Heap::GarbageCollectionEpilogue() {
isolate());
isolate()->heap()->set_dirty_js_weak_factories(weak_factory->next());
weak_factory->set_next(ReadOnlyRoots(isolate()).undefined_value());
Handle<Context> context(weak_factory->native_context(), isolate());
Handle<NativeContext> context(weak_factory->native_context(), isolate());
// GC has no native context, but we use the creation context of the
// JSWeakFactory for the EnqueueTask operation. This is consitent with the
// Promise implementation, assuming the JSFactory creation context is the
@ -965,7 +965,7 @@ void Heap::GarbageCollectionEpilogue() {
// https://github.com/tc39/proposal-weakrefs/issues/38 .
Handle<WeakFactoryCleanupJobTask> task =
isolate()->factory()->NewWeakFactoryCleanupJobTask(weak_factory);
isolate()->EnqueueMicrotask(task);
context->microtask_queue()->EnqueueMicrotask(*task);
}
}
}

View File

@ -100,14 +100,6 @@ void Isolate::FireBeforeCallEnteredCallback() {
}
}
void Isolate::FireMicrotasksCompletedCallback() {
std::vector<MicrotasksCompletedCallback> callbacks(
microtasks_completed_callbacks_);
for (auto& callback : callbacks) {
callback(reinterpret_cast<v8::Isolate*>(this));
}
}
Handle<JSGlobalObject> Isolate::global_object() {
return handle(context()->global_object(), this);
}

View File

@ -4007,28 +4007,12 @@ void Isolate::RemoveCallCompletedCallback(CallCompletedCallback callback) {
call_completed_callbacks_.erase(pos);
}
void Isolate::AddMicrotasksCompletedCallback(
MicrotasksCompletedCallback callback) {
auto pos = std::find(microtasks_completed_callbacks_.begin(),
microtasks_completed_callbacks_.end(), callback);
if (pos != microtasks_completed_callbacks_.end()) return;
microtasks_completed_callbacks_.push_back(callback);
}
void Isolate::RemoveMicrotasksCompletedCallback(
MicrotasksCompletedCallback callback) {
auto pos = std::find(microtasks_completed_callbacks_.begin(),
microtasks_completed_callbacks_.end(), callback);
if (pos == microtasks_completed_callbacks_.end()) return;
microtasks_completed_callbacks_.erase(pos);
}
void Isolate::FireCallCompletedCallback() {
if (!handle_scope_implementer()->CallDepthIsZero()) return;
bool run_microtasks =
default_microtask_queue()->size() &&
!handle_scope_implementer()->HasMicrotasksSuppressions() &&
!default_microtask_queue()->HasMicrotasksSuppressions() &&
handle_scope_implementer()->microtasks_policy() ==
v8::MicrotasksPolicy::kAuto;
@ -4281,22 +4265,12 @@ void Isolate::ReportPromiseReject(Handle<JSPromise> promise,
v8::Utils::StackTraceToLocal(stack_trace)));
}
void Isolate::EnqueueMicrotask(Handle<Microtask> microtask) {
default_microtask_queue()->EnqueueMicrotask(*microtask);
}
void Isolate::RunMicrotasks() {
DCHECK(!is_running_microtasks_);
// TODO(tzik): Move the suppression, |is_running_microtask_|, and the
// completion callbacks into MicrotaskQueue.
// Increase call depth to prevent recursive callbacks.
v8::Isolate::SuppressMicrotaskExecutionScope suppress(
reinterpret_cast<v8::Isolate*>(this));
if (default_microtask_queue()->size()) {
is_running_microtasks_ = true;
MicrotaskQueue* microtask_queue = default_microtask_queue();
if (microtask_queue->size()) {
TRACE_EVENT0("v8.execute", "RunMicrotasks");
TRACE_EVENT_CALL_STATS_SCOPED(this, "v8", "V8.RunMicrotasks");
@ -4304,11 +4278,10 @@ void Isolate::RunMicrotasks() {
handle_scope_implementer());
// If execution is terminating, bail out, clean up, and propagate to
// TryCatch scope.
if (default_microtask_queue()->RunMicrotasks(this) < 0) {
if (microtask_queue->RunMicrotasks(this) < 0) {
SetTerminationOnExternalTryCatch();
}
DCHECK_EQ(0, default_microtask_queue()->size());
is_running_microtasks_ = false;
DCHECK_EQ(0, microtask_queue->size());
}
// TODO(marja): (spec) The discussion about when to clear the KeepDuringJob
// set is still open (whether to clear it after every microtask or once
@ -4316,7 +4289,7 @@ void Isolate::RunMicrotasks() {
// https://github.com/tc39/proposal-weakrefs/issues/39 .
heap()->ClearKeepDuringJobSet();
FireMicrotasksCompletedCallback();
microtask_queue->FireMicrotasksCompletedCallback(this);
}
void Isolate::SetUseCounterCallback(v8::Isolate::UseCounterCallback callback) {

View File

@ -1403,17 +1403,11 @@ class Isolate final : private HiddenFactory {
void RemoveBeforeCallEnteredCallback(BeforeCallEnteredCallback callback);
inline void FireBeforeCallEnteredCallback();
void AddMicrotasksCompletedCallback(MicrotasksCompletedCallback callback);
void RemoveMicrotasksCompletedCallback(MicrotasksCompletedCallback callback);
inline void FireMicrotasksCompletedCallback();
void SetPromiseRejectCallback(PromiseRejectCallback callback);
void ReportPromiseReject(Handle<JSPromise> promise, Handle<Object> value,
v8::PromiseRejectEvent event);
void EnqueueMicrotask(Handle<Microtask> microtask);
void RunMicrotasks();
bool IsRunningMicrotasks() const { return is_running_microtasks_; }
Handle<Symbol> SymbolFor(RootIndex dictionary_index, Handle<String> name,
bool private_symbol);
@ -1856,10 +1850,6 @@ class Isolate final : private HiddenFactory {
// Vector of callbacks when a Call completes.
std::vector<CallCompletedCallback> call_completed_callbacks_;
// Vector of callbacks after microtasks were run.
std::vector<MicrotasksCompletedCallback> microtasks_completed_callbacks_;
bool is_running_microtasks_ = false;
v8::Isolate::UseCounterCallback use_counter_callback_ = nullptr;
std::vector<Object*> read_only_object_cache_;

View File

@ -85,9 +85,31 @@ void MicrotaskQueue::EnqueueMicrotask(Microtask microtask) {
++size_;
}
namespace {
class SetIsRunningMicrotasks {
public:
explicit SetIsRunningMicrotasks(bool* flag) : flag_(flag) {
DCHECK(!*flag_);
*flag_ = true;
}
~SetIsRunningMicrotasks() {
DCHECK(*flag_);
*flag_ = false;
}
private:
bool* flag_;
};
} // namespace
int MicrotaskQueue::RunMicrotasks(Isolate* isolate) {
HandleScope scope(isolate);
HandleScope handle_scope(isolate);
MaybeHandle<Object> maybe_exception;
SetIsRunningMicrotasks scope(&is_running_microtasks_);
MaybeHandle<Object> maybe_result =
Execution::TryRunMicrotasks(isolate, this, &maybe_exception);
@ -132,6 +154,30 @@ void MicrotaskQueue::IterateMicrotasks(RootVisitor* visitor) {
}
}
void MicrotaskQueue::AddMicrotasksCompletedCallback(
MicrotasksCompletedCallback callback) {
auto pos = std::find(microtasks_completed_callbacks_.begin(),
microtasks_completed_callbacks_.end(), callback);
if (pos != microtasks_completed_callbacks_.end()) return;
microtasks_completed_callbacks_.push_back(callback);
}
void MicrotaskQueue::RemoveMicrotasksCompletedCallback(
MicrotasksCompletedCallback callback) {
auto pos = std::find(microtasks_completed_callbacks_.begin(),
microtasks_completed_callbacks_.end(), callback);
if (pos == microtasks_completed_callbacks_.end()) return;
microtasks_completed_callbacks_.erase(pos);
}
void MicrotaskQueue::FireMicrotasksCompletedCallback(Isolate* isolate) const {
std::vector<MicrotasksCompletedCallback> callbacks(
microtasks_completed_callbacks_);
for (auto& callback : callbacks) {
callback(reinterpret_cast<v8::Isolate*>(isolate));
}
}
void MicrotaskQueue::ResizeBuffer(intptr_t new_capacity) {
DCHECK_LE(size_, new_capacity);
Address* new_ring_buffer = new Address[new_capacity];

View File

@ -7,8 +7,10 @@
#include <stdint.h>
#include <memory>
#include <vector>
#include "include/v8-internal.h" // For Address.
#include "include/v8.h"
#include "src/base/macros.h"
namespace v8 {
@ -41,6 +43,35 @@ class V8_EXPORT_PRIVATE MicrotaskQueue {
// builtins can update the queue directly without the write barrier.
void IterateMicrotasks(RootVisitor* visitor);
// Microtasks scope depth represents nested scopes controlling microtasks
// invocation, which happens when depth reaches zero.
void IncrementMicrotasksScopeDepth() { ++microtasks_depth_; }
void DecrementMicrotasksScopeDepth() { --microtasks_depth_; }
int GetMicrotasksScopeDepth() const { return microtasks_depth_; }
// Possibly nested microtasks suppression scopes prevent microtasks
// from running.
void IncrementMicrotasksSuppressions() { ++microtasks_suppressions_; }
void DecrementMicrotasksSuppressions() { --microtasks_suppressions_; }
bool HasMicrotasksSuppressions() const {
return microtasks_suppressions_ != 0;
}
#ifdef DEBUG
// In debug we check that calls not intended to invoke microtasks are
// still correctly wrapped with microtask scopes.
void IncrementDebugMicrotasksScopeDepth() { ++debug_microtasks_depth_; }
void DecrementDebugMicrotasksScopeDepth() { --debug_microtasks_depth_; }
bool DebugMicrotasksScopeDepthIsZero() const {
return debug_microtasks_depth_ == 0;
}
#endif
void AddMicrotasksCompletedCallback(MicrotasksCompletedCallback callback);
void RemoveMicrotasksCompletedCallback(MicrotasksCompletedCallback callback);
void FireMicrotasksCompletedCallback(Isolate* isolate) const;
bool IsRunningMicrotasks() const { return is_running_microtasks_; }
intptr_t capacity() const { return capacity_; }
intptr_t size() const { return size_; }
intptr_t start() const { return start_; }
@ -59,18 +90,27 @@ class V8_EXPORT_PRIVATE MicrotaskQueue {
MicrotaskQueue();
void ResizeBuffer(intptr_t new_capacity);
// A ring buffer to hold Microtask instances.
// ring_buffer_[(start_ + i) % capacity_] contains |i|th Microtask for each
// |i| in [0, size_).
intptr_t size_ = 0;
intptr_t capacity_ = 0;
intptr_t start_ = 0;
Address* ring_buffer_ = nullptr;
// MicrotaskQueue instances form a doubly linked list loop, so that all
// instances are reachable through |next_|.
MicrotaskQueue* next_ = nullptr;
MicrotaskQueue* prev_ = nullptr;
// A ring buffer to hold Microtask instances.
// ring_buffer_[(start_ + i) % capacity_] contains |i|th Microtask for each
// |i| in [0, size_).
Address* ring_buffer_ = nullptr;
intptr_t capacity_ = 0;
intptr_t size_ = 0;
intptr_t start_ = 0;
int microtasks_depth_ = 0;
int microtasks_suppressions_ = 0;
#ifdef DEBUG
int debug_microtasks_depth_ = 0;
#endif
bool is_running_microtasks_ = false;
std::vector<MicrotasksCompletedCallback> microtasks_completed_callbacks_;
};
} // namespace internal

View File

@ -50,6 +50,7 @@
#include "src/macro-assembler.h"
#include "src/map-updater.h"
#include "src/message-template.h"
#include "src/microtask-queue.h"
#include "src/objects-body-descriptors-inl.h"
#include "src/objects/api-callbacks.h"
#include "src/objects/arguments-inl.h"
@ -16554,7 +16555,7 @@ MaybeHandle<Object> JSPromise::Resolve(Handle<JSPromise> promise,
promise, LanguageMode::kStrict)
.Check();
}
isolate->EnqueueMicrotask(task);
isolate->native_context()->microtask_queue()->EnqueueMicrotask(*task);
// 13. Return undefined.
return isolate->factory()->undefined_value();
@ -16620,7 +16621,8 @@ Handle<Object> JSPromise::TriggerPromiseReactions(Isolate* isolate,
PromiseRejectReactionJobTask::kPromiseOrCapabilityOffset));
}
isolate->EnqueueMicrotask(Handle<PromiseReactionJobTask>::cast(task));
isolate->native_context()->microtask_queue()->EnqueueMicrotask(
*Handle<PromiseReactionJobTask>::cast(task));
}
return isolate->factory()->undefined_value();

View File

@ -24,7 +24,7 @@ OBJECT_CONSTRUCTORS_IMPL(JSWeakFactory, JSObject)
OBJECT_CONSTRUCTORS_IMPL(JSWeakFactoryCleanupIterator, JSObject)
OBJECT_CONSTRUCTORS_IMPL(WeakFactoryCleanupJobTask, Microtask)
ACCESSORS2(JSWeakFactory, native_context, Context, kNativeContextOffset)
ACCESSORS2(JSWeakFactory, native_context, NativeContext, kNativeContextOffset)
ACCESSORS(JSWeakFactory, cleanup, Object, kCleanupOffset)
ACCESSORS(JSWeakFactory, active_cells, Object, kActiveCellsOffset)
ACCESSORS(JSWeakFactory, cleared_cells, Object, kClearedCellsOffset)

View File

@ -15,6 +15,7 @@ namespace v8 {
namespace internal {
class JSWeakCell;
class NativeContext;
// WeakFactory object from the JS Weak Refs spec proposal:
// https://github.com/tc39/proposal-weakrefs
@ -24,7 +25,7 @@ class JSWeakFactory : public JSObject {
DECL_VERIFIER(JSWeakFactory)
DECL_CAST2(JSWeakFactory)
DECL_ACCESSORS2(native_context, Context)
DECL_ACCESSORS2(native_context, NativeContext)
DECL_ACCESSORS(cleanup, Object)
DECL_ACCESSORS(active_cells, Object)
DECL_ACCESSORS(cleared_cells, Object)

View File

@ -7,6 +7,7 @@
#include "src/counters.h"
#include "src/debug/debug.h"
#include "src/elements.h"
#include "src/microtask-queue.h"
#include "src/objects-inl.h"
#include "src/objects/heap-object-inl.h"
#include "src/objects/js-promise-inl.h"
@ -77,7 +78,7 @@ RUNTIME_FUNCTION(Runtime_EnqueueMicrotask) {
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Handle<CallableTask> microtask =
isolate->factory()->NewCallableTask(function, isolate->native_context());
isolate->EnqueueMicrotask(microtask);
isolate->native_context()->microtask_queue()->EnqueueMicrotask(*microtask);
return ReadOnlyRoots(isolate).undefined_value();
}

View File

@ -44,7 +44,14 @@ void PartialSerializer::Serialize(Context* o, bool include_global_proxy) {
// Reset math random cache to get fresh random numbers.
MathRandom::ResetContext(context_);
DCHECK_EQ(0, context_->native_context()->microtask_queue()->size());
#ifdef DEBUG
MicrotaskQueue* microtask_queue =
context_->native_context()->microtask_queue();
DCHECK_EQ(0, microtask_queue->size());
DCHECK(!microtask_queue->HasMicrotasksSuppressions());
DCHECK_EQ(0, microtask_queue->GetMicrotasksScopeDepth());
DCHECK(microtask_queue->DebugMicrotasksScopeDepthIsZero());
#endif
context_->native_context()->set_microtask_queue(nullptr);
VisitRootPointer(Root::kPartialSnapshotCache, nullptr, FullObjectSlot(o));