Expose MicrotaskQueue as a V8 API
This introduces v8::MicrotaskQueue backed by v8::internal::MicrotaskQueue. The embedder will get an option to use non-default MicrotaskQueue by creating the instance by v8::MicrotaskQueue::New(). The instance can be attached to a Context by passing it to Context::New(). Bug: v8:8124 Change-Id: Iee0711785d5748860eb94e30a8d83199a743ffaa Reviewed-on: https://chromium-review.googlesource.com/c/1414950 Commit-Queue: Taiju Tsuiki <tzik@chromium.org> Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Reviewed-by: Adam Klein <adamk@chromium.org> Cr-Commit-Position: refs/heads/master@{#59933}
This commit is contained in:
parent
b2f8280e26
commit
cce33f3752
98
include/v8.h
98
include/v8.h
@ -54,6 +54,7 @@ class Integer;
|
||||
class Isolate;
|
||||
template <class T>
|
||||
class Maybe;
|
||||
class MicrotaskQueue;
|
||||
class Name;
|
||||
class Number;
|
||||
class NumberObject;
|
||||
@ -6736,6 +6737,7 @@ typedef void (*PromiseRejectCallback)(PromiseRejectMessage message);
|
||||
|
||||
// --- Microtasks Callbacks ---
|
||||
typedef void (*MicrotasksCompletedCallback)(Isolate*);
|
||||
typedef void (*MicrotasksCompletedCallbackWithData)(Isolate*, void*);
|
||||
typedef void (*MicrotaskCallback)(void* data);
|
||||
|
||||
|
||||
@ -6748,6 +6750,80 @@ typedef void (*MicrotaskCallback)(void* data);
|
||||
*/
|
||||
enum class MicrotasksPolicy { kExplicit, kScoped, kAuto };
|
||||
|
||||
/**
|
||||
* Represents the microtask queue, where microtasks are stored and processed.
|
||||
* https://html.spec.whatwg.org/multipage/webappapis.html#microtask-queue
|
||||
* https://html.spec.whatwg.org/multipage/webappapis.html#enqueuejob(queuename,-job,-arguments)
|
||||
* https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint
|
||||
*
|
||||
* A MicrotaskQueue instance may be associated to multiple Contexts by passing
|
||||
* it to Context::New(), and they can be detached by Context::DetachGlobal().
|
||||
* The embedder must keep the MicrotaskQueue instance alive until all associated
|
||||
* Contexts are gone or detached.
|
||||
*
|
||||
* Use the same instance of MicrotaskQueue for all Contexts that may access each
|
||||
* other synchronously. E.g. for Web embedding, use the same instance for all
|
||||
* origins that share the same URL scheme and eTLD+1.
|
||||
*/
|
||||
class V8_EXPORT MicrotaskQueue {
|
||||
public:
|
||||
/**
|
||||
* Creates an empty MicrotaskQueue instance.
|
||||
*/
|
||||
static std::unique_ptr<MicrotaskQueue> New();
|
||||
|
||||
virtual ~MicrotaskQueue() = default;
|
||||
|
||||
/**
|
||||
* Enqueues the callback to the queue.
|
||||
*/
|
||||
virtual void EnqueueMicrotask(Isolate* isolate,
|
||||
Local<Function> microtask) = 0;
|
||||
|
||||
/**
|
||||
* Enqueues the callback to the queue.
|
||||
*/
|
||||
virtual void EnqueueMicrotask(v8::Isolate* isolate,
|
||||
MicrotaskCallback callback,
|
||||
void* data = nullptr) = 0;
|
||||
|
||||
/**
|
||||
* Adds a callback to notify the embedder after microtasks were run. The
|
||||
* callback is triggered by explicit RunMicrotasks call or automatic
|
||||
* microtasks execution (see Isolate::SetMicrotasksPolicy).
|
||||
*
|
||||
* Callback will trigger even if microtasks were attempted to run,
|
||||
* but the microtasks queue was empty and no single microtask was actually
|
||||
* executed.
|
||||
*
|
||||
* Executing scripts inside the callback will not re-trigger microtasks and
|
||||
* the callback.
|
||||
*/
|
||||
virtual void AddMicrotasksCompletedCallback(
|
||||
MicrotasksCompletedCallbackWithData callback, void* data = nullptr) = 0;
|
||||
|
||||
/**
|
||||
* Removes callback that was installed by AddMicrotasksCompletedCallback.
|
||||
*/
|
||||
virtual void RemoveMicrotasksCompletedCallback(
|
||||
MicrotasksCompletedCallbackWithData callback, void* data = nullptr) = 0;
|
||||
|
||||
/**
|
||||
* Runs microtasks if no microtask is running on this MicrotaskQueue instance.
|
||||
*/
|
||||
virtual void PerformCheckpoint(Isolate* isolate) = 0;
|
||||
|
||||
/**
|
||||
* Returns true if a microtask is running on this MicrotaskQueue instance.
|
||||
*/
|
||||
virtual bool IsRunningMicrotasks() const = 0;
|
||||
|
||||
private:
|
||||
friend class internal::MicrotaskQueue;
|
||||
MicrotaskQueue() = default;
|
||||
MicrotaskQueue(const MicrotaskQueue&) = delete;
|
||||
MicrotaskQueue& operator=(const MicrotaskQueue&) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* This scope is used to control microtasks when kScopeMicrotasksInvocation
|
||||
@ -6763,6 +6839,7 @@ class V8_EXPORT MicrotasksScope {
|
||||
enum Type { kRunMicrotasks, kDoNotRunMicrotasks };
|
||||
|
||||
MicrotasksScope(Isolate* isolate, Type type);
|
||||
MicrotasksScope(Isolate* isolate, MicrotaskQueue* microtask_queue, Type type);
|
||||
~MicrotasksScope();
|
||||
|
||||
/**
|
||||
@ -7432,6 +7509,7 @@ class V8_EXPORT Isolate {
|
||||
class V8_EXPORT SuppressMicrotaskExecutionScope {
|
||||
public:
|
||||
explicit SuppressMicrotaskExecutionScope(Isolate* isolate);
|
||||
explicit SuppressMicrotaskExecutionScope(MicrotaskQueue* microtask_queue);
|
||||
~SuppressMicrotaskExecutionScope();
|
||||
|
||||
// Prevent copying of Scope objects.
|
||||
@ -8107,18 +8185,18 @@ class V8_EXPORT Isolate {
|
||||
void SetPromiseRejectCallback(PromiseRejectCallback callback);
|
||||
|
||||
/**
|
||||
* Runs the Microtask Work Queue until empty
|
||||
* Runs the default MicrotaskQueue until it gets empty.
|
||||
* Any exceptions thrown by microtask callbacks are swallowed.
|
||||
*/
|
||||
void RunMicrotasks();
|
||||
|
||||
/**
|
||||
* Enqueues the callback to the Microtask Work Queue
|
||||
* Enqueues the callback to the default MicrotaskQueue
|
||||
*/
|
||||
void EnqueueMicrotask(Local<Function> microtask);
|
||||
|
||||
/**
|
||||
* Enqueues the callback to the Microtask Work Queue
|
||||
* Enqueues the callback to the default MicrotaskQueue
|
||||
*/
|
||||
void EnqueueMicrotask(MicrotaskCallback callback, void* data = nullptr);
|
||||
|
||||
@ -8134,14 +8212,15 @@ class V8_EXPORT Isolate {
|
||||
|
||||
/**
|
||||
* Adds a callback to notify the host application after
|
||||
* microtasks were run. The callback is triggered by explicit RunMicrotasks
|
||||
* call or automatic microtasks execution (see SetAutorunMicrotasks).
|
||||
* microtasks were run on the default MicrotaskQueue. The callback is
|
||||
* triggered by explicit RunMicrotasks call or automatic microtasks execution
|
||||
* (see SetMicrotaskPolicy).
|
||||
*
|
||||
* Callback will trigger even if microtasks were attempted to run,
|
||||
* but the microtasks queue was empty and no single microtask was actually
|
||||
* executed.
|
||||
*
|
||||
* Executing scriptsinside the callback will not re-trigger microtasks and
|
||||
* Executing scripts inside the callback will not re-trigger microtasks and
|
||||
* the callback.
|
||||
*/
|
||||
void AddMicrotasksCompletedCallback(MicrotasksCompletedCallback callback);
|
||||
@ -9172,7 +9251,8 @@ class V8_EXPORT Context {
|
||||
MaybeLocal<ObjectTemplate> global_template = MaybeLocal<ObjectTemplate>(),
|
||||
MaybeLocal<Value> global_object = MaybeLocal<Value>(),
|
||||
DeserializeInternalFieldsCallback internal_fields_deserializer =
|
||||
DeserializeInternalFieldsCallback());
|
||||
DeserializeInternalFieldsCallback(),
|
||||
MicrotaskQueue* microtask_queue = nullptr);
|
||||
|
||||
/**
|
||||
* Create a new context from a (non-default) context snapshot. There
|
||||
@ -9192,13 +9272,13 @@ class V8_EXPORT Context {
|
||||
*
|
||||
* \param global_object See v8::Context::New.
|
||||
*/
|
||||
|
||||
static MaybeLocal<Context> FromSnapshot(
|
||||
Isolate* isolate, size_t context_snapshot_index,
|
||||
DeserializeInternalFieldsCallback embedder_fields_deserializer =
|
||||
DeserializeInternalFieldsCallback(),
|
||||
ExtensionConfiguration* extensions = nullptr,
|
||||
MaybeLocal<Value> global_object = MaybeLocal<Value>());
|
||||
MaybeLocal<Value> global_object = MaybeLocal<Value>(),
|
||||
MicrotaskQueue* microtask_queue = nullptr);
|
||||
|
||||
/**
|
||||
* Returns an global object that isn't backed by an actual context.
|
||||
|
93
src/api.cc
93
src/api.cc
@ -5880,10 +5880,11 @@ struct InvokeBootstrapper<i::Context> {
|
||||
i::Isolate* isolate, i::MaybeHandle<i::JSGlobalProxy> maybe_global_proxy,
|
||||
v8::Local<v8::ObjectTemplate> global_proxy_template,
|
||||
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
|
||||
v8::DeserializeInternalFieldsCallback embedder_fields_deserializer) {
|
||||
v8::DeserializeInternalFieldsCallback embedder_fields_deserializer,
|
||||
v8::MicrotaskQueue* microtask_queue) {
|
||||
return isolate->bootstrapper()->CreateEnvironment(
|
||||
maybe_global_proxy, global_proxy_template, extensions,
|
||||
context_snapshot_index, embedder_fields_deserializer);
|
||||
context_snapshot_index, embedder_fields_deserializer, microtask_queue);
|
||||
}
|
||||
};
|
||||
|
||||
@ -5893,7 +5894,8 @@ struct InvokeBootstrapper<i::JSGlobalProxy> {
|
||||
i::Isolate* isolate, i::MaybeHandle<i::JSGlobalProxy> maybe_global_proxy,
|
||||
v8::Local<v8::ObjectTemplate> global_proxy_template,
|
||||
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
|
||||
v8::DeserializeInternalFieldsCallback embedder_fields_deserializer) {
|
||||
v8::DeserializeInternalFieldsCallback embedder_fields_deserializer,
|
||||
v8::MicrotaskQueue* microtask_queue) {
|
||||
USE(extensions);
|
||||
USE(context_snapshot_index);
|
||||
return isolate->bootstrapper()->NewRemoteContext(maybe_global_proxy,
|
||||
@ -5906,7 +5908,8 @@ static i::Handle<ObjectType> CreateEnvironment(
|
||||
i::Isolate* isolate, v8::ExtensionConfiguration* extensions,
|
||||
v8::MaybeLocal<ObjectTemplate> maybe_global_template,
|
||||
v8::MaybeLocal<Value> maybe_global_proxy, size_t context_snapshot_index,
|
||||
v8::DeserializeInternalFieldsCallback embedder_fields_deserializer) {
|
||||
v8::DeserializeInternalFieldsCallback embedder_fields_deserializer,
|
||||
v8::MicrotaskQueue* microtask_queue) {
|
||||
i::Handle<ObjectType> result;
|
||||
|
||||
{
|
||||
@ -5982,9 +5985,9 @@ static i::Handle<ObjectType> CreateEnvironment(
|
||||
}
|
||||
// Create the environment.
|
||||
InvokeBootstrapper<ObjectType> invoke;
|
||||
result =
|
||||
invoke.Invoke(isolate, maybe_proxy, proxy_template, extensions,
|
||||
context_snapshot_index, embedder_fields_deserializer);
|
||||
result = invoke.Invoke(isolate, maybe_proxy, proxy_template, extensions,
|
||||
context_snapshot_index, embedder_fields_deserializer,
|
||||
microtask_queue);
|
||||
|
||||
// Restore the access check info and interceptors on the global template.
|
||||
if (!maybe_global_template.IsEmpty()) {
|
||||
@ -6010,7 +6013,8 @@ Local<Context> NewContext(
|
||||
v8::Isolate* external_isolate, v8::ExtensionConfiguration* extensions,
|
||||
v8::MaybeLocal<ObjectTemplate> global_template,
|
||||
v8::MaybeLocal<Value> global_object, size_t context_snapshot_index,
|
||||
v8::DeserializeInternalFieldsCallback embedder_fields_deserializer) {
|
||||
v8::DeserializeInternalFieldsCallback embedder_fields_deserializer,
|
||||
v8::MicrotaskQueue* microtask_queue) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(external_isolate);
|
||||
// TODO(jkummerow): This is for crbug.com/713699. Remove it if it doesn't
|
||||
// fail.
|
||||
@ -6024,7 +6028,7 @@ Local<Context> NewContext(
|
||||
if (extensions == nullptr) extensions = &no_extensions;
|
||||
i::Handle<i::Context> env = CreateEnvironment<i::Context>(
|
||||
isolate, extensions, global_template, global_object,
|
||||
context_snapshot_index, embedder_fields_deserializer);
|
||||
context_snapshot_index, embedder_fields_deserializer, microtask_queue);
|
||||
if (env.is_null()) {
|
||||
if (isolate->has_pending_exception()) isolate->clear_pending_exception();
|
||||
return Local<Context>();
|
||||
@ -6036,15 +6040,18 @@ Local<Context> v8::Context::New(
|
||||
v8::Isolate* external_isolate, v8::ExtensionConfiguration* extensions,
|
||||
v8::MaybeLocal<ObjectTemplate> global_template,
|
||||
v8::MaybeLocal<Value> global_object,
|
||||
DeserializeInternalFieldsCallback internal_fields_deserializer) {
|
||||
DeserializeInternalFieldsCallback internal_fields_deserializer,
|
||||
v8::MicrotaskQueue* microtask_queue) {
|
||||
return NewContext(external_isolate, extensions, global_template,
|
||||
global_object, 0, internal_fields_deserializer);
|
||||
global_object, 0, internal_fields_deserializer,
|
||||
microtask_queue);
|
||||
}
|
||||
|
||||
MaybeLocal<Context> v8::Context::FromSnapshot(
|
||||
v8::Isolate* external_isolate, size_t context_snapshot_index,
|
||||
v8::DeserializeInternalFieldsCallback embedder_fields_deserializer,
|
||||
v8::ExtensionConfiguration* extensions, MaybeLocal<Value> global_object) {
|
||||
v8::ExtensionConfiguration* extensions, MaybeLocal<Value> global_object,
|
||||
v8::MicrotaskQueue* microtask_queue) {
|
||||
size_t index_including_default_context = context_snapshot_index + 1;
|
||||
if (!i::Snapshot::HasContextSnapshot(
|
||||
reinterpret_cast<i::Isolate*>(external_isolate),
|
||||
@ -6053,7 +6060,7 @@ MaybeLocal<Context> v8::Context::FromSnapshot(
|
||||
}
|
||||
return NewContext(external_isolate, extensions, MaybeLocal<ObjectTemplate>(),
|
||||
global_object, index_including_default_context,
|
||||
embedder_fields_deserializer);
|
||||
embedder_fields_deserializer, microtask_queue);
|
||||
}
|
||||
|
||||
MaybeLocal<Object> v8::Context::NewRemoteContext(
|
||||
@ -6074,9 +6081,9 @@ MaybeLocal<Object> v8::Context::NewRemoteContext(
|
||||
"v8::Context::NewRemoteContext",
|
||||
"Global template needs to have access check handlers.");
|
||||
i::Handle<i::JSGlobalProxy> global_proxy =
|
||||
CreateEnvironment<i::JSGlobalProxy>(isolate, nullptr, global_template,
|
||||
global_object, 0,
|
||||
DeserializeInternalFieldsCallback());
|
||||
CreateEnvironment<i::JSGlobalProxy>(
|
||||
isolate, nullptr, global_template, global_object, 0,
|
||||
DeserializeInternalFieldsCallback(), nullptr);
|
||||
if (global_proxy.is_null()) {
|
||||
if (isolate->has_pending_exception()) isolate->clear_pending_exception();
|
||||
return MaybeLocal<Object>();
|
||||
@ -8546,15 +8553,11 @@ void Isolate::RunMicrotasks() {
|
||||
void Isolate::EnqueueMicrotask(Local<Function> v8_function) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
i::Handle<i::JSReceiver> function = Utils::OpenHandle(*v8_function);
|
||||
|
||||
i::Handle<i::NativeContext> handler_context;
|
||||
if (!i::JSReceiver::GetContextForMicrotask(function).ToHandle(
|
||||
&handler_context))
|
||||
handler_context = isolate->native_context();
|
||||
|
||||
i::Handle<i::CallableTask> microtask =
|
||||
isolate->factory()->NewCallableTask(function, handler_context);
|
||||
handler_context->microtask_queue()->EnqueueMicrotask(*microtask);
|
||||
handler_context->microtask_queue()->EnqueueMicrotask(this, v8_function);
|
||||
}
|
||||
|
||||
void Isolate::EnqueueMicrotask(MicrotaskCallback callback, void* data) {
|
||||
@ -8579,12 +8582,21 @@ MicrotasksPolicy Isolate::GetMicrotasksPolicy() const {
|
||||
return isolate->default_microtask_queue()->microtasks_policy();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void MicrotasksCompletedCallbackAdapter(v8::Isolate* isolate, void* data) {
|
||||
auto callback = reinterpret_cast<MicrotasksCompletedCallback>(data);
|
||||
callback(isolate);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Isolate::AddMicrotasksCompletedCallback(
|
||||
MicrotasksCompletedCallback callback) {
|
||||
DCHECK(callback);
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->default_microtask_queue()->AddMicrotasksCompletedCallback(callback);
|
||||
isolate->default_microtask_queue()->AddMicrotasksCompletedCallback(
|
||||
&MicrotasksCompletedCallbackAdapter, reinterpret_cast<void*>(callback));
|
||||
}
|
||||
|
||||
|
||||
@ -8592,7 +8604,7 @@ void Isolate::RemoveMicrotasksCompletedCallback(
|
||||
MicrotasksCompletedCallback callback) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->default_microtask_queue()->RemoveMicrotasksCompletedCallback(
|
||||
callback);
|
||||
&MicrotasksCompletedCallbackAdapter, reinterpret_cast<void*>(callback));
|
||||
}
|
||||
|
||||
|
||||
@ -8892,8 +8904,16 @@ void Isolate::SetAllowAtomicsWait(bool allow) {
|
||||
}
|
||||
|
||||
MicrotasksScope::MicrotasksScope(Isolate* isolate, MicrotasksScope::Type type)
|
||||
: MicrotasksScope(
|
||||
isolate,
|
||||
reinterpret_cast<i::Isolate*>(isolate)->default_microtask_queue(),
|
||||
type) {}
|
||||
|
||||
MicrotasksScope::MicrotasksScope(Isolate* isolate,
|
||||
MicrotaskQueue* microtask_queue,
|
||||
MicrotasksScope::Type type)
|
||||
: isolate_(reinterpret_cast<i::Isolate*>(isolate)),
|
||||
microtask_queue_(isolate_->default_microtask_queue()),
|
||||
microtask_queue_(static_cast<i::MicrotaskQueue*>(microtask_queue)),
|
||||
run_(type == MicrotasksScope::kRunMicrotasks) {
|
||||
if (run_) microtask_queue_->IncrementMicrotasksScopeDepth();
|
||||
#ifdef DEBUG
|
||||
@ -8913,25 +8933,22 @@ MicrotasksScope::~MicrotasksScope() {
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void MicrotasksScope::PerformCheckpoint(Isolate* v8Isolate) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8Isolate);
|
||||
void MicrotasksScope::PerformCheckpoint(Isolate* v8_isolate) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
|
||||
auto* microtask_queue = isolate->default_microtask_queue();
|
||||
if (!microtask_queue->GetMicrotasksScopeDepth() &&
|
||||
!microtask_queue->HasMicrotasksSuppressions()) {
|
||||
microtask_queue->RunMicrotasks(isolate);
|
||||
}
|
||||
microtask_queue->PerformCheckpoint(v8_isolate);
|
||||
}
|
||||
|
||||
|
||||
int MicrotasksScope::GetCurrentDepth(Isolate* v8Isolate) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8Isolate);
|
||||
return isolate->default_microtask_queue()->GetMicrotasksScopeDepth();
|
||||
int MicrotasksScope::GetCurrentDepth(Isolate* v8_isolate) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
|
||||
auto* microtask_queue = isolate->default_microtask_queue();
|
||||
return microtask_queue->GetMicrotasksScopeDepth();
|
||||
}
|
||||
|
||||
bool MicrotasksScope::IsRunningMicrotasks(Isolate* v8Isolate) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8Isolate);
|
||||
return isolate->default_microtask_queue()->IsRunningMicrotasks();
|
||||
bool MicrotasksScope::IsRunningMicrotasks(Isolate* v8_isolate) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
|
||||
auto* microtask_queue = isolate->default_microtask_queue();
|
||||
return microtask_queue->IsRunningMicrotasks();
|
||||
}
|
||||
|
||||
String::Utf8Value::Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> obj)
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/isolate-inl.h"
|
||||
#include "src/math-random.h"
|
||||
#include "src/microtask-queue.h"
|
||||
#include "src/objects/api-callbacks.h"
|
||||
#include "src/objects/arguments.h"
|
||||
#include "src/objects/builtin-function-id.h"
|
||||
@ -139,7 +140,8 @@ class Genesis {
|
||||
Genesis(Isolate* isolate, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
|
||||
v8::Local<v8::ObjectTemplate> global_proxy_template,
|
||||
size_t context_snapshot_index,
|
||||
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer);
|
||||
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer,
|
||||
v8::MicrotaskQueue* microtask_queue);
|
||||
Genesis(Isolate* isolate, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
|
||||
v8::Local<v8::ObjectTemplate> global_proxy_template);
|
||||
~Genesis() = default;
|
||||
@ -302,12 +304,14 @@ Handle<Context> Bootstrapper::CreateEnvironment(
|
||||
MaybeHandle<JSGlobalProxy> maybe_global_proxy,
|
||||
v8::Local<v8::ObjectTemplate> global_proxy_template,
|
||||
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
|
||||
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
|
||||
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer,
|
||||
v8::MicrotaskQueue* microtask_queue) {
|
||||
HandleScope scope(isolate_);
|
||||
Handle<Context> env;
|
||||
{
|
||||
Genesis genesis(isolate_, maybe_global_proxy, global_proxy_template,
|
||||
context_snapshot_index, embedder_fields_deserializer);
|
||||
context_snapshot_index, embedder_fields_deserializer,
|
||||
microtask_queue);
|
||||
env = genesis.result();
|
||||
if (env.is_null() || !InstallExtensions(env, extensions)) {
|
||||
return Handle<Context>();
|
||||
@ -5504,7 +5508,8 @@ Genesis::Genesis(
|
||||
Isolate* isolate, MaybeHandle<JSGlobalProxy> maybe_global_proxy,
|
||||
v8::Local<v8::ObjectTemplate> global_proxy_template,
|
||||
size_t context_snapshot_index,
|
||||
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer)
|
||||
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer,
|
||||
v8::MicrotaskQueue* microtask_queue)
|
||||
: isolate_(isolate), active_(isolate->bootstrapper()) {
|
||||
RuntimeCallTimerScope rcs_timer(isolate, RuntimeCallCounterId::kGenesis);
|
||||
result_ = Handle<Context>::null();
|
||||
@ -5600,7 +5605,9 @@ Genesis::Genesis(
|
||||
}
|
||||
}
|
||||
|
||||
native_context()->set_microtask_queue(isolate->default_microtask_queue());
|
||||
native_context()->set_microtask_queue(
|
||||
microtask_queue ? static_cast<MicrotaskQueue*>(microtask_queue)
|
||||
: isolate->default_microtask_queue());
|
||||
|
||||
// Install experimental natives. Do not include them into the
|
||||
// snapshot as we should be able to turn them off at runtime. Re-installing
|
||||
|
@ -57,7 +57,8 @@ class Bootstrapper final {
|
||||
MaybeHandle<JSGlobalProxy> maybe_global_proxy,
|
||||
v8::Local<v8::ObjectTemplate> global_object_template,
|
||||
v8::ExtensionConfiguration* extensions, size_t context_snapshot_index,
|
||||
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer);
|
||||
v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer,
|
||||
v8::MicrotaskQueue* microtask_queue);
|
||||
|
||||
Handle<JSGlobalProxy> NewRemoteContext(
|
||||
MaybeHandle<JSGlobalProxy> maybe_global_proxy,
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <stddef.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "src/api.h"
|
||||
#include "src/api-inl.h"
|
||||
#include "src/base/logging.h"
|
||||
#include "src/handles-inl.h"
|
||||
#include "src/isolate.h"
|
||||
@ -77,6 +77,26 @@ Address MicrotaskQueue::CallEnqueueMicrotask(Isolate* isolate,
|
||||
return ReadOnlyRoots(isolate).undefined_value().ptr();
|
||||
}
|
||||
|
||||
void MicrotaskQueue::EnqueueMicrotask(v8::Isolate* v8_isolate,
|
||||
v8::Local<Function> function) {
|
||||
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
|
||||
HandleScope scope(isolate);
|
||||
Handle<CallableTask> microtask = isolate->factory()->NewCallableTask(
|
||||
Utils::OpenHandle(*function), isolate->native_context());
|
||||
EnqueueMicrotask(*microtask);
|
||||
}
|
||||
|
||||
void MicrotaskQueue::EnqueueMicrotask(v8::Isolate* v8_isolate,
|
||||
v8::MicrotaskCallback callback,
|
||||
void* data) {
|
||||
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
|
||||
HandleScope scope(isolate);
|
||||
Handle<CallbackTask> microtask = isolate->factory()->NewCallbackTask(
|
||||
isolate->factory()->NewForeign(reinterpret_cast<Address>(callback)),
|
||||
isolate->factory()->NewForeign(reinterpret_cast<Address>(data)));
|
||||
EnqueueMicrotask(*microtask);
|
||||
}
|
||||
|
||||
void MicrotaskQueue::EnqueueMicrotask(Microtask microtask) {
|
||||
if (size_ == capacity_) {
|
||||
// Keep the capacity of |ring_buffer_| power of 2, so that the JIT
|
||||
@ -90,6 +110,14 @@ void MicrotaskQueue::EnqueueMicrotask(Microtask microtask) {
|
||||
++size_;
|
||||
}
|
||||
|
||||
void MicrotaskQueue::PerformCheckpoint(v8::Isolate* v8_isolate) {
|
||||
if (!IsRunningMicrotasks() && !GetMicrotasksScopeDepth() &&
|
||||
!HasMicrotasksSuppressions()) {
|
||||
Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
|
||||
RunMicrotasks(isolate);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class SetIsRunningMicrotasks {
|
||||
@ -184,26 +212,29 @@ void MicrotaskQueue::IterateMicrotasks(RootVisitor* visitor) {
|
||||
}
|
||||
|
||||
void MicrotaskQueue::AddMicrotasksCompletedCallback(
|
||||
MicrotasksCompletedCallback callback) {
|
||||
auto pos = std::find(microtasks_completed_callbacks_.begin(),
|
||||
microtasks_completed_callbacks_.end(), callback);
|
||||
MicrotasksCompletedCallbackWithData callback, void* data) {
|
||||
CallbackWithData callback_with_data(callback, data);
|
||||
auto pos =
|
||||
std::find(microtasks_completed_callbacks_.begin(),
|
||||
microtasks_completed_callbacks_.end(), callback_with_data);
|
||||
if (pos != microtasks_completed_callbacks_.end()) return;
|
||||
microtasks_completed_callbacks_.push_back(callback);
|
||||
microtasks_completed_callbacks_.push_back(callback_with_data);
|
||||
}
|
||||
|
||||
void MicrotaskQueue::RemoveMicrotasksCompletedCallback(
|
||||
MicrotasksCompletedCallback callback) {
|
||||
auto pos = std::find(microtasks_completed_callbacks_.begin(),
|
||||
microtasks_completed_callbacks_.end(), callback);
|
||||
MicrotasksCompletedCallbackWithData callback, void* data) {
|
||||
CallbackWithData callback_with_data(callback, data);
|
||||
auto pos =
|
||||
std::find(microtasks_completed_callbacks_.begin(),
|
||||
microtasks_completed_callbacks_.end(), callback_with_data);
|
||||
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_);
|
||||
std::vector<CallbackWithData> callbacks(microtasks_completed_callbacks_);
|
||||
for (auto& callback : callbacks) {
|
||||
callback(reinterpret_cast<v8::Isolate*>(isolate));
|
||||
callback.first(reinterpret_cast<v8::Isolate*>(isolate), callback.second);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,7 @@ class Microtask;
|
||||
class Object;
|
||||
class RootVisitor;
|
||||
|
||||
class V8_EXPORT_PRIVATE MicrotaskQueue {
|
||||
class V8_EXPORT_PRIVATE MicrotaskQueue final : public v8::MicrotaskQueue {
|
||||
public:
|
||||
static void SetUpDefaultMicrotaskQueue(Isolate* isolate);
|
||||
static std::unique_ptr<MicrotaskQueue> New(Isolate* isolate);
|
||||
@ -35,7 +35,19 @@ class V8_EXPORT_PRIVATE MicrotaskQueue {
|
||||
intptr_t microtask_queue_pointer,
|
||||
Address raw_microtask);
|
||||
|
||||
// v8::MicrotaskQueue implementations.
|
||||
void EnqueueMicrotask(v8::Isolate* isolate,
|
||||
v8::Local<Function> microtask) override;
|
||||
void EnqueueMicrotask(v8::Isolate* isolate, v8::MicrotaskCallback callback,
|
||||
void* data) override;
|
||||
void PerformCheckpoint(v8::Isolate* isolate) override;
|
||||
|
||||
void EnqueueMicrotask(Microtask microtask);
|
||||
void AddMicrotasksCompletedCallback(
|
||||
MicrotasksCompletedCallbackWithData callback, void* data) override;
|
||||
void RemoveMicrotasksCompletedCallback(
|
||||
MicrotasksCompletedCallbackWithData callback, void* data) override;
|
||||
bool IsRunningMicrotasks() const override { return is_running_microtasks_; }
|
||||
|
||||
// Runs all queued Microtasks.
|
||||
// Returns -1 if the execution is terminating, otherwise, returns the number
|
||||
@ -78,7 +90,6 @@ class V8_EXPORT_PRIVATE MicrotaskQueue {
|
||||
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_; }
|
||||
@ -128,7 +139,9 @@ class V8_EXPORT_PRIVATE MicrotaskQueue {
|
||||
v8::MicrotasksPolicy microtasks_policy_ = v8::MicrotasksPolicy::kAuto;
|
||||
|
||||
bool is_running_microtasks_ = false;
|
||||
std::vector<MicrotasksCompletedCallback> microtasks_completed_callbacks_;
|
||||
using CallbackWithData =
|
||||
std::pair<MicrotasksCompletedCallbackWithData, void*>;
|
||||
std::vector<CallbackWithData> microtasks_completed_callbacks_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
Loading…
Reference in New Issue
Block a user