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:
parent
c6d8c75557
commit
f2c2742c50
40
src/api.cc
40
src/api.cc
@ -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)
|
||||
|
40
src/api.h
40
src/api.h
@ -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_;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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_;
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user