Reland "Implement Faster MicrotaskQueue Step 2"
This is an attempt to reland https://crrev.com/1d726111ab7087a5, that was reverted at https://crrev.com/0a820125230bec24. Tbr: bmeurer@chromium.org Bug: chromium:887920, v8:7253 Change-Id: I785417de7d0560b93bda5ade623fa5be3647d7dd Reviewed-on: https://chromium-review.googlesource.com/c/1350530 Commit-Queue: Taiju Tsuiki <tzik@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#57865}
This commit is contained in:
parent
ca39f55ae1
commit
3a437ce47a
5
BUILD.gn
5
BUILD.gn
@ -2256,6 +2256,8 @@ v8_source_set("v8_base") {
|
||||
"src/message-template.h",
|
||||
"src/messages.cc",
|
||||
"src/messages.h",
|
||||
"src/microtask-queue.cc",
|
||||
"src/microtask-queue.h",
|
||||
"src/msan.h",
|
||||
"src/objects-body-descriptors-inl.h",
|
||||
"src/objects-body-descriptors.h",
|
||||
@ -2358,9 +2360,6 @@ v8_source_set("v8_base") {
|
||||
"src/objects/maybe-object-inl.h",
|
||||
"src/objects/maybe-object.h",
|
||||
"src/objects/microtask-inl.h",
|
||||
"src/objects/microtask-queue-inl.h",
|
||||
"src/objects/microtask-queue.cc",
|
||||
"src/objects/microtask-queue.h",
|
||||
"src/objects/microtask.h",
|
||||
"src/objects/module-inl.h",
|
||||
"src/objects/module.cc",
|
||||
|
@ -5884,6 +5884,9 @@ Genesis::Genesis(
|
||||
}
|
||||
}
|
||||
|
||||
native_context()->set_microtask_queue_pointer(
|
||||
reinterpret_cast<Object*>(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
|
||||
// them after they have already been deserialized would also fail.
|
||||
|
@ -5,9 +5,9 @@
|
||||
#include "src/api.h"
|
||||
#include "src/builtins/builtins-utils-gen.h"
|
||||
#include "src/code-stub-assembler.h"
|
||||
#include "src/microtask-queue.h"
|
||||
#include "src/objects/js-weak-refs.h"
|
||||
#include "src/objects/microtask-inl.h"
|
||||
#include "src/objects/microtask-queue.h"
|
||||
#include "src/objects/promise.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -21,78 +21,90 @@ class MicrotaskQueueBuiltinsAssembler : public CodeStubAssembler {
|
||||
explicit MicrotaskQueueBuiltinsAssembler(compiler::CodeAssemblerState* state)
|
||||
: CodeStubAssembler(state) {}
|
||||
|
||||
TNode<MicrotaskQueue> GetDefaultMicrotaskQueue();
|
||||
TNode<IntPtrT> GetPendingMicrotaskCount(
|
||||
TNode<MicrotaskQueue> microtask_queue);
|
||||
void SetPendingMicrotaskCount(TNode<MicrotaskQueue> microtask_queue,
|
||||
TNode<IntPtrT> new_num_tasks);
|
||||
TNode<FixedArray> GetQueuedMicrotasks(TNode<MicrotaskQueue> microtask_queue);
|
||||
void SetQueuedMicrotasks(TNode<MicrotaskQueue> microtask_queue,
|
||||
TNode<FixedArray> new_queue);
|
||||
TNode<IntPtrT> GetDefaultMicrotaskQueue();
|
||||
TNode<IntPtrT> GetMicrotaskQueue(TNode<Context> context);
|
||||
TNode<IntPtrT> GetMicrotaskRingBuffer(TNode<IntPtrT> microtask_queue);
|
||||
TNode<IntPtrT> GetMicrotaskQueueCapacity(TNode<IntPtrT> microtask_queue);
|
||||
TNode<IntPtrT> GetMicrotaskQueueSize(TNode<IntPtrT> microtask_queue);
|
||||
void SetMicrotaskQueueSize(TNode<IntPtrT> microtask_queue,
|
||||
TNode<IntPtrT> new_size);
|
||||
TNode<IntPtrT> GetMicrotaskQueueStart(TNode<IntPtrT> microtask_queue);
|
||||
void SetMicrotaskQueueStart(TNode<IntPtrT> microtask_queue,
|
||||
TNode<IntPtrT> new_start);
|
||||
TNode<IntPtrT> CalculateRingBufferOffset(TNode<IntPtrT> capacity,
|
||||
TNode<IntPtrT> start,
|
||||
TNode<IntPtrT> index);
|
||||
void RunSingleMicrotask(TNode<Context> current_context,
|
||||
TNode<Microtask> microtask);
|
||||
|
||||
TNode<Context> GetCurrentContext();
|
||||
void SetCurrentContext(TNode<Context> context);
|
||||
|
||||
void EnterMicrotaskContext(TNode<Context> context);
|
||||
void EnterMicrotaskContext(TNode<Context> native_context);
|
||||
void LeaveMicrotaskContext();
|
||||
|
||||
void RunPromiseHook(Runtime::FunctionId id, TNode<Context> context,
|
||||
SloppyTNode<HeapObject> promise_or_capability);
|
||||
|
||||
TNode<Object> GetPendingException() {
|
||||
auto ref = ExternalReference::Create(kPendingExceptionAddress, isolate());
|
||||
return TNode<Object>::UncheckedCast(
|
||||
Load(MachineType::AnyTagged(), ExternalConstant(ref)));
|
||||
}
|
||||
void ClearPendingException() {
|
||||
auto ref = ExternalReference::Create(kPendingExceptionAddress, isolate());
|
||||
StoreNoWriteBarrier(MachineRepresentation::kTagged, ExternalConstant(ref),
|
||||
TheHoleConstant());
|
||||
}
|
||||
|
||||
TNode<Object> GetScheduledException() {
|
||||
auto ref = ExternalReference::scheduled_exception_address(isolate());
|
||||
return TNode<Object>::UncheckedCast(
|
||||
Load(MachineType::AnyTagged(), ExternalConstant(ref)));
|
||||
}
|
||||
void ClearScheduledException() {
|
||||
auto ref = ExternalReference::scheduled_exception_address(isolate());
|
||||
StoreNoWriteBarrier(MachineRepresentation::kTagged, ExternalConstant(ref),
|
||||
TheHoleConstant());
|
||||
}
|
||||
};
|
||||
|
||||
TNode<MicrotaskQueue>
|
||||
MicrotaskQueueBuiltinsAssembler::GetDefaultMicrotaskQueue() {
|
||||
return TNode<MicrotaskQueue>::UncheckedCast(
|
||||
LoadRoot(RootIndex::kDefaultMicrotaskQueue));
|
||||
TNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetDefaultMicrotaskQueue() {
|
||||
auto ref = ExternalReference::default_microtask_queue_address(isolate());
|
||||
return UncheckedCast<IntPtrT>(
|
||||
Load(MachineType::Pointer(), ExternalConstant(ref)));
|
||||
}
|
||||
|
||||
TNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetPendingMicrotaskCount(
|
||||
TNode<MicrotaskQueue> microtask_queue) {
|
||||
TNode<IntPtrT> result = LoadAndUntagObjectField(
|
||||
microtask_queue, MicrotaskQueue::kPendingMicrotaskCountOffset);
|
||||
return result;
|
||||
TNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueue(
|
||||
TNode<Context> context) {
|
||||
// TODO(ishell): move microtask queue pointer to embedder data array.
|
||||
int offset = Context::SlotOffset(Context::MICROTASK_QUEUE_POINTER);
|
||||
return UncheckedCast<IntPtrT>(
|
||||
Load(MachineType::Pointer(), context, IntPtrConstant(offset)));
|
||||
}
|
||||
|
||||
void MicrotaskQueueBuiltinsAssembler::SetPendingMicrotaskCount(
|
||||
TNode<MicrotaskQueue> microtask_queue, TNode<IntPtrT> new_num_tasks) {
|
||||
StoreObjectField(microtask_queue,
|
||||
MicrotaskQueue::kPendingMicrotaskCountOffset,
|
||||
SmiFromIntPtr(new_num_tasks));
|
||||
TNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskRingBuffer(
|
||||
TNode<IntPtrT> microtask_queue) {
|
||||
return UncheckedCast<IntPtrT>(
|
||||
Load(MachineType::IntPtr(), microtask_queue,
|
||||
IntPtrConstant(MicrotaskQueue::kRingBufferOffset)));
|
||||
}
|
||||
|
||||
TNode<FixedArray> MicrotaskQueueBuiltinsAssembler::GetQueuedMicrotasks(
|
||||
TNode<MicrotaskQueue> microtask_queue) {
|
||||
return LoadObjectField<FixedArray>(microtask_queue,
|
||||
MicrotaskQueue::kQueueOffset);
|
||||
TNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueueCapacity(
|
||||
TNode<IntPtrT> microtask_queue) {
|
||||
return UncheckedCast<IntPtrT>(
|
||||
Load(MachineType::IntPtr(), microtask_queue,
|
||||
IntPtrConstant(MicrotaskQueue::kCapacityOffset)));
|
||||
}
|
||||
|
||||
void MicrotaskQueueBuiltinsAssembler::SetQueuedMicrotasks(
|
||||
TNode<MicrotaskQueue> microtask_queue, TNode<FixedArray> new_queue) {
|
||||
StoreObjectField(microtask_queue, MicrotaskQueue::kQueueOffset, new_queue);
|
||||
TNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueueSize(
|
||||
TNode<IntPtrT> microtask_queue) {
|
||||
return UncheckedCast<IntPtrT>(
|
||||
Load(MachineType::IntPtr(), microtask_queue,
|
||||
IntPtrConstant(MicrotaskQueue::kSizeOffset)));
|
||||
}
|
||||
|
||||
void MicrotaskQueueBuiltinsAssembler::SetMicrotaskQueueSize(
|
||||
TNode<IntPtrT> microtask_queue, TNode<IntPtrT> new_size) {
|
||||
StoreNoWriteBarrier(MachineType::PointerRepresentation(), microtask_queue,
|
||||
IntPtrConstant(MicrotaskQueue::kSizeOffset), new_size);
|
||||
}
|
||||
|
||||
TNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::GetMicrotaskQueueStart(
|
||||
TNode<IntPtrT> microtask_queue) {
|
||||
return UncheckedCast<IntPtrT>(
|
||||
Load(MachineType::IntPtr(), microtask_queue,
|
||||
IntPtrConstant(MicrotaskQueue::kStartOffset)));
|
||||
}
|
||||
|
||||
void MicrotaskQueueBuiltinsAssembler::SetMicrotaskQueueStart(
|
||||
TNode<IntPtrT> microtask_queue, TNode<IntPtrT> new_start) {
|
||||
StoreNoWriteBarrier(MachineType::PointerRepresentation(), microtask_queue,
|
||||
IntPtrConstant(MicrotaskQueue::kStartOffset), new_start);
|
||||
}
|
||||
|
||||
TNode<IntPtrT> MicrotaskQueueBuiltinsAssembler::CalculateRingBufferOffset(
|
||||
TNode<IntPtrT> capacity, TNode<IntPtrT> start, TNode<IntPtrT> index) {
|
||||
return TimesPointerSize(
|
||||
WordAnd(IntPtrAdd(start, index), IntPtrSub(capacity, IntPtrConstant(1))));
|
||||
}
|
||||
|
||||
void MicrotaskQueueBuiltinsAssembler::RunSingleMicrotask(
|
||||
@ -394,110 +406,87 @@ void MicrotaskQueueBuiltinsAssembler::RunPromiseHook(
|
||||
}
|
||||
|
||||
TF_BUILTIN(EnqueueMicrotask, MicrotaskQueueBuiltinsAssembler) {
|
||||
Node* microtask = Parameter(Descriptor::kMicrotask);
|
||||
TNode<Microtask> microtask =
|
||||
UncheckedCast<Microtask>(Parameter(Descriptor::kMicrotask));
|
||||
TNode<Context> context =
|
||||
UncheckedCast<Context>(Parameter(Descriptor::kContext));
|
||||
TNode<Context> native_context = LoadNativeContext(context);
|
||||
TNode<IntPtrT> microtask_queue = GetMicrotaskQueue(native_context);
|
||||
|
||||
TNode<MicrotaskQueue> microtask_queue = GetDefaultMicrotaskQueue();
|
||||
TNode<IntPtrT> num_tasks = GetPendingMicrotaskCount(microtask_queue);
|
||||
TNode<IntPtrT> new_num_tasks = IntPtrAdd(num_tasks, IntPtrConstant(1));
|
||||
TNode<FixedArray> queue = GetQueuedMicrotasks(microtask_queue);
|
||||
TNode<IntPtrT> queue_length = LoadAndUntagFixedArrayBaseLength(queue);
|
||||
TNode<IntPtrT> ring_buffer = GetMicrotaskRingBuffer(microtask_queue);
|
||||
TNode<IntPtrT> capacity = GetMicrotaskQueueCapacity(microtask_queue);
|
||||
TNode<IntPtrT> size = GetMicrotaskQueueSize(microtask_queue);
|
||||
TNode<IntPtrT> start = GetMicrotaskQueueStart(microtask_queue);
|
||||
|
||||
Label if_append(this), if_grow(this), done(this);
|
||||
Branch(WordEqual(num_tasks, queue_length), &if_grow, &if_append);
|
||||
Label if_grow(this);
|
||||
GotoIf(IntPtrEqual(size, capacity), &if_grow);
|
||||
|
||||
// |microtask_queue| has an unused slot to store |microtask|.
|
||||
{
|
||||
StoreNoWriteBarrier(MachineType::PointerRepresentation(), ring_buffer,
|
||||
CalculateRingBufferOffset(capacity, start, size),
|
||||
BitcastTaggedToWord(microtask));
|
||||
StoreNoWriteBarrier(MachineType::PointerRepresentation(), microtask_queue,
|
||||
IntPtrConstant(MicrotaskQueue::kSizeOffset),
|
||||
IntPtrAdd(size, IntPtrConstant(1)));
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
// |microtask_queue| has no space to store |microtask|. Fall back to C++
|
||||
// implementation to grow the buffer.
|
||||
BIND(&if_grow);
|
||||
{
|
||||
// Determine the new queue length and check if we need to allocate
|
||||
// in large object space (instead of just going to new space, where
|
||||
// we also know that we don't need any write barriers for setting
|
||||
// up the new queue object).
|
||||
Label if_newspace(this), if_lospace(this, Label::kDeferred);
|
||||
TNode<IntPtrT> new_queue_length =
|
||||
IntPtrMax(IntPtrConstant(8), IntPtrAdd(num_tasks, num_tasks));
|
||||
Branch(IntPtrLessThanOrEqual(new_queue_length,
|
||||
IntPtrConstant(FixedArray::kMaxRegularLength)),
|
||||
&if_newspace, &if_lospace);
|
||||
|
||||
BIND(&if_newspace);
|
||||
{
|
||||
// This is the likely case where the new queue fits into new space,
|
||||
// and thus we don't need any write barriers for initializing it.
|
||||
TNode<FixedArray> new_queue =
|
||||
CAST(AllocateFixedArray(PACKED_ELEMENTS, new_queue_length));
|
||||
CopyFixedArrayElements(PACKED_ELEMENTS, queue, new_queue, num_tasks,
|
||||
SKIP_WRITE_BARRIER);
|
||||
StoreFixedArrayElement(new_queue, num_tasks, microtask,
|
||||
SKIP_WRITE_BARRIER);
|
||||
FillFixedArrayWithValue(PACKED_ELEMENTS, new_queue, new_num_tasks,
|
||||
new_queue_length, RootIndex::kUndefinedValue);
|
||||
SetQueuedMicrotasks(microtask_queue, new_queue);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&if_lospace);
|
||||
{
|
||||
// The fallback case where the new queue ends up in large object space.
|
||||
TNode<FixedArray> new_queue = CAST(AllocateFixedArray(
|
||||
PACKED_ELEMENTS, new_queue_length, INTPTR_PARAMETERS,
|
||||
AllocationFlag::kAllowLargeObjectAllocation));
|
||||
CopyFixedArrayElements(PACKED_ELEMENTS, queue, new_queue, num_tasks);
|
||||
StoreFixedArrayElement(new_queue, num_tasks, microtask);
|
||||
FillFixedArrayWithValue(PACKED_ELEMENTS, new_queue, new_num_tasks,
|
||||
new_queue_length, RootIndex::kUndefinedValue);
|
||||
SetQueuedMicrotasks(microtask_queue, new_queue);
|
||||
Goto(&done);
|
||||
}
|
||||
Node* isolate_constant =
|
||||
ExternalConstant(ExternalReference::isolate_address(isolate()));
|
||||
Node* function =
|
||||
ExternalConstant(ExternalReference::call_enqueue_microtask_function());
|
||||
CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
|
||||
MachineType::IntPtr(), MachineType::AnyTagged(), function,
|
||||
isolate_constant, microtask_queue, microtask);
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
BIND(&if_append);
|
||||
{
|
||||
StoreFixedArrayElement(queue, num_tasks, microtask);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&done);
|
||||
SetPendingMicrotaskCount(microtask_queue, new_num_tasks);
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
TF_BUILTIN(RunMicrotasks, MicrotaskQueueBuiltinsAssembler) {
|
||||
// Load the current context from the isolate.
|
||||
TNode<Context> current_context = GetCurrentContext();
|
||||
TNode<MicrotaskQueue> microtask_queue = GetDefaultMicrotaskQueue();
|
||||
|
||||
Label init_queue_loop(this), done_init_queue_loop(this);
|
||||
Goto(&init_queue_loop);
|
||||
BIND(&init_queue_loop);
|
||||
{
|
||||
TVARIABLE(IntPtrT, index, IntPtrConstant(0));
|
||||
Label loop(this, &index);
|
||||
// TODO(tzik): Take a MicrotaskQueue parameter to support non-default queue.
|
||||
TNode<IntPtrT> microtask_queue = GetDefaultMicrotaskQueue();
|
||||
|
||||
TNode<IntPtrT> num_tasks = GetPendingMicrotaskCount(microtask_queue);
|
||||
GotoIf(IntPtrEqual(num_tasks, IntPtrConstant(0)), &done_init_queue_loop);
|
||||
Label loop(this), done(this);
|
||||
Goto(&loop);
|
||||
BIND(&loop);
|
||||
|
||||
TNode<FixedArray> queue = GetQueuedMicrotasks(microtask_queue);
|
||||
TNode<IntPtrT> size = GetMicrotaskQueueSize(microtask_queue);
|
||||
|
||||
CSA_ASSERT(this, IntPtrGreaterThanOrEqual(
|
||||
LoadAndUntagFixedArrayBaseLength(queue), num_tasks));
|
||||
CSA_ASSERT(this, IntPtrGreaterThan(num_tasks, IntPtrConstant(0)));
|
||||
// Exit if the queue is empty.
|
||||
GotoIf(WordEqual(size, IntPtrConstant(0)), &done);
|
||||
|
||||
SetQueuedMicrotasks(microtask_queue, EmptyFixedArrayConstant());
|
||||
SetPendingMicrotaskCount(microtask_queue, IntPtrConstant(0));
|
||||
TNode<IntPtrT> ring_buffer = GetMicrotaskRingBuffer(microtask_queue);
|
||||
TNode<IntPtrT> capacity = GetMicrotaskQueueCapacity(microtask_queue);
|
||||
TNode<IntPtrT> start = GetMicrotaskQueueStart(microtask_queue);
|
||||
|
||||
Goto(&loop);
|
||||
BIND(&loop);
|
||||
{
|
||||
TNode<Microtask> microtask =
|
||||
CAST(LoadFixedArrayElement(queue, index.value()));
|
||||
index = IntPtrAdd(index.value(), IntPtrConstant(1));
|
||||
TNode<IntPtrT> offset =
|
||||
CalculateRingBufferOffset(capacity, start, IntPtrConstant(0));
|
||||
TNode<IntPtrT> microtask_pointer =
|
||||
UncheckedCast<IntPtrT>(Load(MachineType::Pointer(), ring_buffer, offset));
|
||||
TNode<Microtask> microtask =
|
||||
UncheckedCast<Microtask>(BitcastWordToTagged(microtask_pointer));
|
||||
|
||||
CSA_ASSERT(this, TaggedIsNotSmi(microtask));
|
||||
RunSingleMicrotask(current_context, microtask);
|
||||
Branch(IntPtrLessThan(index.value(), num_tasks), &loop, &init_queue_loop);
|
||||
}
|
||||
}
|
||||
TNode<IntPtrT> new_size = IntPtrSub(size, IntPtrConstant(1));
|
||||
TNode<IntPtrT> new_start = WordAnd(IntPtrAdd(start, IntPtrConstant(1)),
|
||||
IntPtrSub(capacity, IntPtrConstant(1)));
|
||||
|
||||
BIND(&done_init_queue_loop);
|
||||
// Remove |microtask| from |ring_buffer| before running it, since its
|
||||
// invocation may add another microtask into |ring_buffer|.
|
||||
SetMicrotaskQueueSize(microtask_queue, new_size);
|
||||
SetMicrotaskQueueStart(microtask_queue, new_start);
|
||||
|
||||
RunSingleMicrotask(current_context, microtask);
|
||||
Goto(&loop);
|
||||
|
||||
BIND(&done);
|
||||
{
|
||||
// Reset the "current microtask" on the isolate.
|
||||
StoreRoot(RootIndex::kCurrentMicrotask, UndefinedConstant());
|
||||
|
@ -377,7 +377,7 @@ void PromiseBuiltinsAssembler::PerformPromiseThen(
|
||||
Node* microtask = AllocatePromiseReactionJobTask(
|
||||
var_map.value(), context, argument, var_handler.value(),
|
||||
result_promise_or_capability);
|
||||
CallBuiltin(Builtins::kEnqueueMicrotask, NoContextConstant(), microtask);
|
||||
CallBuiltin(Builtins::kEnqueueMicrotask, context, microtask);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
@ -531,7 +531,7 @@ Node* PromiseBuiltinsAssembler::TriggerPromiseReactions(
|
||||
STATIC_ASSERT(PromiseReaction::kPromiseOrCapabilityOffset ==
|
||||
PromiseReactionJobTask::kPromiseOrCapabilityOffset);
|
||||
}
|
||||
CallBuiltin(Builtins::kEnqueueMicrotask, NoContextConstant(), current);
|
||||
CallBuiltin(Builtins::kEnqueueMicrotask, context, current);
|
||||
Goto(&loop);
|
||||
}
|
||||
BIND(&done_loop);
|
||||
|
@ -317,7 +317,6 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
|
||||
case PROPERTY_CELL_TYPE:
|
||||
case MODULE_TYPE:
|
||||
case MODULE_INFO_ENTRY_TYPE:
|
||||
case MICROTASK_QUEUE_TYPE:
|
||||
case CELL_TYPE:
|
||||
case PRE_PARSED_SCOPE_DATA_TYPE:
|
||||
case UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE:
|
||||
|
@ -273,6 +273,9 @@ enum ContextLookupFlags {
|
||||
V(PROMISE_ALL_RESOLVE_ELEMENT_SHARED_FUN, SharedFunctionInfo, \
|
||||
promise_all_resolve_element_shared_fun) \
|
||||
V(PROMISE_PROTOTYPE_INDEX, JSObject, promise_prototype) \
|
||||
/* TODO(ishell): [ptr-compr] this field contains a pointer to a C++ */ \
|
||||
/* object */ \
|
||||
V(MICROTASK_QUEUE_POINTER, Object, microtask_queue_pointer) \
|
||||
V(REGEXP_EXEC_FUNCTION_INDEX, JSFunction, regexp_exec_function) \
|
||||
V(REGEXP_FUNCTION_INDEX, JSFunction, regexp_function) \
|
||||
V(REGEXP_LAST_MATCH_INFO_INDEX, RegExpMatchInfo, regexp_last_match_info) \
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "src/interpreter/interpreter.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/math-random.h"
|
||||
#include "src/microtask-queue.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/regexp/regexp-stack.h"
|
||||
#include "src/simulator-base.h"
|
||||
@ -135,6 +136,11 @@ ExternalReference ExternalReference::handle_scope_implementer_address(
|
||||
return ExternalReference(isolate->handle_scope_implementer_address());
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::default_microtask_queue_address(
|
||||
Isolate* isolate) {
|
||||
return ExternalReference(isolate->default_microtask_queue_address());
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::interpreter_dispatch_table_address(
|
||||
Isolate* isolate) {
|
||||
return ExternalReference(isolate->interpreter()->dispatch_table_address());
|
||||
@ -830,6 +836,11 @@ ExternalReference ExternalReference::fixed_typed_array_base_data_offset() {
|
||||
FixedTypedArrayBase::kDataOffset - kHeapObjectTag));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::call_enqueue_microtask_function() {
|
||||
return ExternalReference(
|
||||
Redirect(FUNCTION_ADDR(MicrotaskQueue::CallEnqueueMicrotask)));
|
||||
}
|
||||
|
||||
static int64_t atomic_pair_load(intptr_t address) {
|
||||
return std::atomic_load(reinterpret_cast<std::atomic<int64_t>*>(address));
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ class StatsCounter;
|
||||
V(builtins_address, "builtins") \
|
||||
V(handle_scope_implementer_address, \
|
||||
"Isolate::handle_scope_implementer_address") \
|
||||
V(default_microtask_queue_address, \
|
||||
"Isolate::default_microtask_queue_address()") \
|
||||
V(address_of_interpreter_entry_trampoline_instruction_start, \
|
||||
"Address of the InterpreterEntryTrampoline instruction start") \
|
||||
V(interpreter_dispatch_counters, "Interpreter::dispatch_counters") \
|
||||
@ -179,6 +181,7 @@ class StatsCounter;
|
||||
V(wasm_word32_ror, "wasm::word32_ror") \
|
||||
V(wasm_word64_ctz, "wasm::word64_ctz") \
|
||||
V(wasm_word64_popcnt, "wasm::word64_popcnt") \
|
||||
V(call_enqueue_microtask_function, "MicrotaskQueue::CallEnqueueMicrotask") \
|
||||
V(atomic_pair_load_function, "atomic_pair_load_function") \
|
||||
V(atomic_pair_store_function, "atomic_pair_store_function") \
|
||||
V(atomic_pair_add_function, "atomic_pair_add_function") \
|
||||
|
@ -31,7 +31,6 @@
|
||||
#include "src/objects/js-weak-refs-inl.h"
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
#include "src/objects/microtask-inl.h"
|
||||
#include "src/objects/microtask-queue-inl.h"
|
||||
#include "src/objects/module-inl.h"
|
||||
#include "src/objects/promise-inl.h"
|
||||
#include "src/objects/scope-info.h"
|
||||
@ -1722,16 +1721,6 @@ Handle<WeakFactoryCleanupJobTask> Factory::NewWeakFactoryCleanupJobTask(
|
||||
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) {
|
||||
// Statically ensure that it is safe to allocate foreigns in paged spaces.
|
||||
STATIC_ASSERT(Foreign::kSize <= kMaxRegularHeapObjectSize);
|
||||
|
@ -452,8 +452,6 @@ class V8_EXPORT_PRIVATE Factory {
|
||||
Handle<WeakFactoryCleanupJobTask> NewWeakFactoryCleanupJobTask(
|
||||
Handle<JSWeakFactory> weak_factory);
|
||||
|
||||
Handle<MicrotaskQueue> NewMicrotaskQueue();
|
||||
|
||||
// Foreign objects are pretenured when allocated by the bootstrapper.
|
||||
Handle<Foreign> NewForeign(Address addr,
|
||||
PretenureFlag pretenure = NOT_TENURED);
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "src/objects/api-callbacks-inl.h"
|
||||
#include "src/objects/descriptor-array.h"
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
#include "src/objects/microtask-queue-inl.h"
|
||||
#include "src/objects/scope-info.h"
|
||||
#include "src/objects/script-inl.h"
|
||||
#include "src/profiler/heap-profiler.h"
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include "src/heap/stress-scavenge-observer.h"
|
||||
#include "src/heap/sweeper.h"
|
||||
#include "src/interpreter/interpreter.h"
|
||||
#include "src/microtask-queue.h"
|
||||
#include "src/objects/data-handler.h"
|
||||
#include "src/objects/hash-table-inl.h"
|
||||
#include "src/objects/maybe-object.h"
|
||||
@ -3888,6 +3889,16 @@ void Heap::IterateStrongRoots(RootVisitor* v, VisitMode mode) {
|
||||
}
|
||||
v->Synchronize(VisitorSynchronization::kStrongRoots);
|
||||
|
||||
// Iterate over pending Microtasks stored in MicrotaskQueues.
|
||||
MicrotaskQueue* default_microtask_queue = isolate_->default_microtask_queue();
|
||||
if (default_microtask_queue) {
|
||||
MicrotaskQueue* microtask_queue = default_microtask_queue;
|
||||
do {
|
||||
microtask_queue->IterateMicrotasks(v);
|
||||
microtask_queue = microtask_queue->next();
|
||||
} while (microtask_queue != default_microtask_queue);
|
||||
}
|
||||
|
||||
// Iterate over the partial snapshot cache unless serializing or
|
||||
// deserializing.
|
||||
if (mode != VISIT_FOR_SERIALIZATION) {
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "src/objects/js-weak-refs.h"
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
#include "src/objects/map.h"
|
||||
#include "src/objects/microtask-queue.h"
|
||||
#include "src/objects/microtask.h"
|
||||
#include "src/objects/module.h"
|
||||
#include "src/objects/promise.h"
|
||||
@ -774,8 +773,6 @@ void Heap::CreateInitialObjects() {
|
||||
Handle<FeedbackCell> no_feedback_cell = factory->NewNoFeedbackCell();
|
||||
set_no_feedback_cell(*no_feedback_cell);
|
||||
|
||||
set_default_microtask_queue(*factory->NewMicrotaskQueue());
|
||||
|
||||
{
|
||||
Handle<FixedArray> empty_sloppy_arguments_elements =
|
||||
factory->NewFixedArray(2, TENURED_READ_ONLY);
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "src/libsampler/sampler.h"
|
||||
#include "src/log.h"
|
||||
#include "src/messages.h"
|
||||
#include "src/microtask-queue.h"
|
||||
#include "src/objects/frame-array-inl.h"
|
||||
#include "src/objects/hash-table-inl.h"
|
||||
#include "src/objects/js-array-inl.h"
|
||||
@ -2810,6 +2811,8 @@ Isolate::Isolate(std::unique_ptr<i::IsolateAllocator> isolate_allocator)
|
||||
debug_ = new Debug(this);
|
||||
|
||||
InitializeDefaultEmbeddedBlob();
|
||||
|
||||
MicrotaskQueue::SetUpDefaultMicrotaskQueue(this);
|
||||
}
|
||||
|
||||
void Isolate::CheckIsolateLayout() {
|
||||
@ -3015,6 +3018,12 @@ Isolate::~Isolate() {
|
||||
|
||||
delete allocator_;
|
||||
allocator_ = nullptr;
|
||||
|
||||
// Assert that |default_microtask_queue_| is the last MicrotaskQueue instance.
|
||||
DCHECK_IMPLIES(default_microtask_queue_,
|
||||
default_microtask_queue_ == default_microtask_queue_->next());
|
||||
delete default_microtask_queue_;
|
||||
default_microtask_queue_ = nullptr;
|
||||
}
|
||||
|
||||
void Isolate::InitializeThreadLocal() { thread_local_top_.Initialize(this); }
|
||||
@ -4017,7 +4026,7 @@ void Isolate::FireCallCompletedCallback() {
|
||||
if (!handle_scope_implementer()->CallDepthIsZero()) return;
|
||||
|
||||
bool run_microtasks =
|
||||
heap()->default_microtask_queue()->pending_microtask_count() &&
|
||||
default_microtask_queue()->size() &&
|
||||
!handle_scope_implementer()->HasMicrotasksSuppressions() &&
|
||||
handle_scope_implementer()->microtasks_policy() ==
|
||||
v8::MicrotasksPolicy::kAuto;
|
||||
@ -4272,37 +4281,29 @@ void Isolate::ReportPromiseReject(Handle<JSPromise> promise,
|
||||
}
|
||||
|
||||
void Isolate::EnqueueMicrotask(Handle<Microtask> microtask) {
|
||||
Handle<MicrotaskQueue> microtask_queue(heap()->default_microtask_queue(),
|
||||
this);
|
||||
MicrotaskQueue::EnqueueMicrotask(this, microtask_queue, microtask);
|
||||
default_microtask_queue()->EnqueueMicrotask(*microtask);
|
||||
}
|
||||
|
||||
|
||||
void Isolate::RunMicrotasks() {
|
||||
// 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));
|
||||
HandleScope scope(this);
|
||||
Handle<MicrotaskQueue> microtask_queue(heap()->default_microtask_queue(),
|
||||
this);
|
||||
if (microtask_queue->pending_microtask_count()) {
|
||||
if (default_microtask_queue()->size()) {
|
||||
is_running_microtasks_ = true;
|
||||
TRACE_EVENT0("v8.execute", "RunMicrotasks");
|
||||
TRACE_EVENT_CALL_STATS_SCOPED(this, "v8", "V8.RunMicrotasks");
|
||||
|
||||
MaybeHandle<Object> maybe_exception;
|
||||
MaybeHandle<Object> maybe_result = Execution::RunMicrotasks(
|
||||
this, Execution::MessageHandling::kReport, &maybe_exception);
|
||||
// If execution is terminating, bail out, clean up, and propagate to
|
||||
// TryCatch scope.
|
||||
if (maybe_result.is_null() && maybe_exception.is_null()) {
|
||||
microtask_queue->set_queue(ReadOnlyRoots(heap()).empty_fixed_array());
|
||||
microtask_queue->set_pending_microtask_count(0);
|
||||
if (default_microtask_queue()->RunMicrotasks(this) < 0) {
|
||||
handle_scope_implementer()->LeaveMicrotaskContext();
|
||||
SetTerminationOnExternalTryCatch();
|
||||
}
|
||||
CHECK_EQ(0, microtask_queue->pending_microtask_count());
|
||||
CHECK_EQ(0, microtask_queue->queue()->length());
|
||||
DCHECK_EQ(0, default_microtask_queue()->size());
|
||||
is_running_microtasks_ = false;
|
||||
}
|
||||
// TODO(marja): (spec) The discussion about when to clear the KeepDuringJob
|
||||
|
@ -84,6 +84,7 @@ class InnerPointerToCodeCache;
|
||||
class Logger;
|
||||
class MaterializedObjectStore;
|
||||
class Microtask;
|
||||
class MicrotaskQueue;
|
||||
class OptimizingCompileDispatcher;
|
||||
class PromiseOnStack;
|
||||
class RegExpStack;
|
||||
@ -477,6 +478,7 @@ typedef std::vector<HeapObject*> DebugObjectCache;
|
||||
V(const intptr_t*, api_external_references, nullptr) \
|
||||
V(AddressToIndexHashMap*, external_reference_map, nullptr) \
|
||||
V(HeapObjectToIndexHashMap*, root_index_map, nullptr) \
|
||||
V(MicrotaskQueue*, default_microtask_queue, nullptr) \
|
||||
V(CompilationStatistics*, turbo_statistics, nullptr) \
|
||||
V(CodeTracer*, code_tracer, nullptr) \
|
||||
V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu) \
|
||||
@ -1430,6 +1432,10 @@ class Isolate final : private HiddenFactory {
|
||||
return reinterpret_cast<Address>(&promise_hook_or_async_event_delegate_);
|
||||
}
|
||||
|
||||
Address default_microtask_queue_address() {
|
||||
return reinterpret_cast<Address>(&default_microtask_queue_);
|
||||
}
|
||||
|
||||
Address promise_hook_or_debug_is_active_or_async_event_delegate_address() {
|
||||
return reinterpret_cast<Address>(
|
||||
&promise_hook_or_debug_is_active_or_async_event_delegate_);
|
||||
@ -1817,7 +1823,7 @@ class Isolate final : private HiddenFactory {
|
||||
// preprocessor defines. Make sure the offsets of these fields agree
|
||||
// between compilation units.
|
||||
#define ISOLATE_FIELD_OFFSET(type, name, ignored) \
|
||||
static const intptr_t name##_debug_offset_;
|
||||
V8_EXPORT_PRIVATE static const intptr_t name##_debug_offset_;
|
||||
ISOLATE_INIT_LIST(ISOLATE_FIELD_OFFSET)
|
||||
ISOLATE_INIT_ARRAY_LIST(ISOLATE_FIELD_OFFSET)
|
||||
#undef ISOLATE_FIELD_OFFSET
|
||||
|
151
src/microtask-queue.cc
Normal file
151
src/microtask-queue.cc
Normal file
@ -0,0 +1,151 @@
|
||||
// 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/microtask-queue.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "src/base/logging.h"
|
||||
#include "src/handles-inl.h"
|
||||
#include "src/isolate.h"
|
||||
#include "src/objects/microtask.h"
|
||||
#include "src/roots-inl.h"
|
||||
#include "src/visitors.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
const size_t MicrotaskQueue::kRingBufferOffset =
|
||||
offsetof(MicrotaskQueue, ring_buffer_);
|
||||
const size_t MicrotaskQueue::kCapacityOffset =
|
||||
offsetof(MicrotaskQueue, capacity_);
|
||||
const size_t MicrotaskQueue::kSizeOffset = offsetof(MicrotaskQueue, size_);
|
||||
const size_t MicrotaskQueue::kStartOffset = offsetof(MicrotaskQueue, start_);
|
||||
|
||||
const intptr_t MicrotaskQueue::kMinimumCapacity = 8;
|
||||
|
||||
// static
|
||||
void MicrotaskQueue::SetUpDefaultMicrotaskQueue(Isolate* isolate) {
|
||||
DCHECK_NULL(isolate->default_microtask_queue());
|
||||
|
||||
MicrotaskQueue* microtask_queue = new MicrotaskQueue;
|
||||
microtask_queue->next_ = microtask_queue;
|
||||
microtask_queue->prev_ = microtask_queue;
|
||||
isolate->set_default_microtask_queue(microtask_queue);
|
||||
}
|
||||
|
||||
// static
|
||||
std::unique_ptr<MicrotaskQueue> MicrotaskQueue::New(Isolate* isolate) {
|
||||
DCHECK_NOT_NULL(isolate->default_microtask_queue());
|
||||
|
||||
std::unique_ptr<MicrotaskQueue> microtask_queue(new MicrotaskQueue);
|
||||
|
||||
// Insert the new instance to the next of last MicrotaskQueue instance.
|
||||
MicrotaskQueue* last = isolate->default_microtask_queue()->prev_;
|
||||
microtask_queue->next_ = last->next_;
|
||||
microtask_queue->prev_ = last;
|
||||
last->next_->prev_ = microtask_queue.get();
|
||||
last->next_ = microtask_queue.get();
|
||||
|
||||
return microtask_queue;
|
||||
}
|
||||
|
||||
MicrotaskQueue::MicrotaskQueue() = default;
|
||||
|
||||
MicrotaskQueue::~MicrotaskQueue() {
|
||||
if (next_ != this) {
|
||||
DCHECK_NE(prev_, this);
|
||||
next_->prev_ = prev_;
|
||||
prev_->next_ = next_;
|
||||
}
|
||||
delete[] ring_buffer_;
|
||||
}
|
||||
|
||||
// static
|
||||
Object* MicrotaskQueue::CallEnqueueMicrotask(Isolate* isolate,
|
||||
intptr_t microtask_queue_pointer,
|
||||
Microtask* microtask) {
|
||||
reinterpret_cast<MicrotaskQueue*>(microtask_queue_pointer)
|
||||
->EnqueueMicrotask(microtask);
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
void MicrotaskQueue::EnqueueMicrotask(Microtask* microtask) {
|
||||
if (size_ == capacity_) {
|
||||
// Keep the capacity of |ring_buffer_| power of 2, so that the JIT
|
||||
// implementation can calculate the modulo easily.
|
||||
intptr_t new_capacity = std::max(kMinimumCapacity, capacity_ << 1);
|
||||
ResizeBuffer(new_capacity);
|
||||
}
|
||||
|
||||
DCHECK_LT(size_, capacity_);
|
||||
ring_buffer_[(start_ + size_) % capacity_] = microtask;
|
||||
++size_;
|
||||
}
|
||||
|
||||
int MicrotaskQueue::RunMicrotasks(Isolate* isolate) {
|
||||
HandleScope scope(isolate);
|
||||
MaybeHandle<Object> maybe_exception;
|
||||
|
||||
// TODO(tzik): Execution::RunMicrotasks() runs default_microtask_queue.
|
||||
// Give it as a parameter to support non-default MicrotaskQueue.
|
||||
DCHECK_EQ(this, isolate->default_microtask_queue());
|
||||
MaybeHandle<Object> maybe_result = Execution::RunMicrotasks(
|
||||
isolate, Execution::MessageHandling::kReport, &maybe_exception);
|
||||
|
||||
// If execution is terminating, clean up and propagate that to the caller.
|
||||
if (maybe_result.is_null() && maybe_exception.is_null()) {
|
||||
delete[] ring_buffer_;
|
||||
ring_buffer_ = nullptr;
|
||||
capacity_ = 0;
|
||||
size_ = 0;
|
||||
start_ = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO(tzik): Return the number of microtasks run in this round.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MicrotaskQueue::IterateMicrotasks(RootVisitor* visitor) {
|
||||
if (!size_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Iterate pending Microtasks as root objects to avoid the write barrier for
|
||||
// all single Microtask. If this hurts the GC performance, use a FixedArray.
|
||||
visitor->VisitRootPointers(
|
||||
Root::kStrongRoots, nullptr, ObjectSlot(ring_buffer_ + start_),
|
||||
ObjectSlot(ring_buffer_ + std::min(start_ + size_, capacity_)));
|
||||
visitor->VisitRootPointers(
|
||||
Root::kStrongRoots, nullptr, ObjectSlot(ring_buffer_),
|
||||
ObjectSlot(ring_buffer_ + std::max(start_ + size_ - capacity_,
|
||||
static_cast<intptr_t>(0))));
|
||||
|
||||
intptr_t new_capacity = capacity_;
|
||||
while (new_capacity > 2 * size_) {
|
||||
new_capacity >>= 1;
|
||||
}
|
||||
new_capacity = std::max(new_capacity, kMinimumCapacity);
|
||||
if (new_capacity < capacity_) {
|
||||
ResizeBuffer(new_capacity);
|
||||
}
|
||||
}
|
||||
|
||||
void MicrotaskQueue::ResizeBuffer(intptr_t new_capacity) {
|
||||
DCHECK_LE(size_, new_capacity);
|
||||
Object** new_ring_buffer = new Object*[new_capacity];
|
||||
for (intptr_t i = 0; i < size_; ++i) {
|
||||
new_ring_buffer[i] = ring_buffer_[(start_ + i) % capacity_];
|
||||
}
|
||||
|
||||
delete[] ring_buffer_;
|
||||
ring_buffer_ = new_ring_buffer;
|
||||
capacity_ = new_capacity;
|
||||
start_ = 0;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
78
src/microtask-queue.h
Normal file
78
src/microtask-queue.h
Normal file
@ -0,0 +1,78 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_MICROTASK_QUEUE_H_
|
||||
#define V8_MICROTASK_QUEUE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <memory>
|
||||
|
||||
#include "src/base/macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class Isolate;
|
||||
class Microtask;
|
||||
class Object;
|
||||
class RootVisitor;
|
||||
|
||||
class V8_EXPORT_PRIVATE MicrotaskQueue {
|
||||
public:
|
||||
static void SetUpDefaultMicrotaskQueue(Isolate* isolate);
|
||||
static std::unique_ptr<MicrotaskQueue> New(Isolate* isolate);
|
||||
|
||||
~MicrotaskQueue();
|
||||
|
||||
static Object* CallEnqueueMicrotask(Isolate* isolate,
|
||||
intptr_t microtask_queue_pointer,
|
||||
Microtask* microtask);
|
||||
|
||||
void EnqueueMicrotask(Microtask* microtask);
|
||||
|
||||
// Returns -1 if the execution is terminating, otherwise, returns 0.
|
||||
// TODO(tzik): Update the implementation to return the number of processed
|
||||
// microtasks.
|
||||
int RunMicrotasks(Isolate* isolate);
|
||||
|
||||
// Iterate all pending Microtasks in this queue as strong roots, so that
|
||||
// builtins can update the queue directly without the write barrier.
|
||||
void IterateMicrotasks(RootVisitor* visitor);
|
||||
|
||||
intptr_t capacity() const { return capacity_; }
|
||||
intptr_t size() const { return size_; }
|
||||
intptr_t start() const { return start_; }
|
||||
|
||||
MicrotaskQueue* next() const { return next_; }
|
||||
MicrotaskQueue* prev() const { return prev_; }
|
||||
|
||||
static const size_t kRingBufferOffset;
|
||||
static const size_t kCapacityOffset;
|
||||
static const size_t kSizeOffset;
|
||||
static const size_t kStartOffset;
|
||||
|
||||
static const intptr_t kMinimumCapacity;
|
||||
|
||||
private:
|
||||
MicrotaskQueue();
|
||||
void ResizeBuffer(intptr_t new_capacity);
|
||||
|
||||
// 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_).
|
||||
Object** ring_buffer_ = nullptr;
|
||||
intptr_t capacity_ = 0;
|
||||
intptr_t size_ = 0;
|
||||
intptr_t start_ = 0;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_MICROTASK_QUEUE_H_
|
@ -47,7 +47,6 @@
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
#include "src/objects/maybe-object.h"
|
||||
#include "src/objects/microtask-inl.h"
|
||||
#include "src/objects/microtask-queue-inl.h"
|
||||
#include "src/objects/module-inl.h"
|
||||
#include "src/objects/promise-inl.h"
|
||||
#include "src/objects/stack-frame-info-inl.h"
|
||||
@ -1415,13 +1414,6 @@ void PromiseReactionJobTask::PromiseReactionJobTaskVerify(Isolate* isolate) {
|
||||
promise_or_capability()->IsUndefined(isolate));
|
||||
}
|
||||
|
||||
void MicrotaskQueue::MicrotaskQueueVerify(Isolate* isolate) {
|
||||
CHECK(IsMicrotaskQueue());
|
||||
VerifyHeapPointer(isolate, queue());
|
||||
VerifySmiField(kPendingMicrotaskCountOffset);
|
||||
CHECK_LE(pending_microtask_count(), queue()->length());
|
||||
}
|
||||
|
||||
void PromiseFulfillReactionJobTask::PromiseFulfillReactionJobTaskVerify(
|
||||
Isolate* isolate) {
|
||||
CHECK(IsPromiseFulfillReactionJobTask());
|
||||
|
@ -124,8 +124,6 @@ namespace internal {
|
||||
V(PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE) \
|
||||
V(WEAK_FACTORY_CLEANUP_JOB_TASK_TYPE) \
|
||||
\
|
||||
V(MICROTASK_QUEUE_TYPE) \
|
||||
\
|
||||
V(ALLOCATION_SITE_TYPE) \
|
||||
V(EMBEDDER_DATA_ARRAY_TYPE) \
|
||||
\
|
||||
@ -353,8 +351,7 @@ namespace internal {
|
||||
V(_, PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE, PromiseResolveThenableJobTask, \
|
||||
promise_resolve_thenable_job_task) \
|
||||
V(_, WEAK_FACTORY_CLEANUP_JOB_TASK_TYPE, WeakFactoryCleanupJobTask, \
|
||||
weak_factory_cleanup_job_task) \
|
||||
V(_, MICROTASK_QUEUE_TYPE, MicrotaskQueue, microtask_queue)
|
||||
weak_factory_cleanup_job_task)
|
||||
|
||||
// Adapts one STRUCT_LIST_GENERATOR entry to the STRUCT_LIST entry
|
||||
#define STRUCT_LIST_ADAPTER(V, NAME, Name, name) V(NAME, Name, name)
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "src/objects/js-weak-refs-inl.h"
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
#include "src/objects/microtask-inl.h"
|
||||
#include "src/objects/microtask-queue-inl.h"
|
||||
#include "src/objects/module-inl.h"
|
||||
#include "src/objects/promise-inl.h"
|
||||
#include "src/objects/stack-frame-info-inl.h"
|
||||
@ -2347,13 +2346,6 @@ void UncompiledDataWithPreParsedScope::UncompiledDataWithPreParsedScopePrint(
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
void MicrotaskQueue::MicrotaskQueuePrint(std::ostream& os) { // NOLINT
|
||||
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
|
||||
HeapObject::PrintHeader(os, "InterpreterData");
|
||||
os << "\n - bytecode_array: " << Brief(bytecode_array());
|
||||
|
@ -86,7 +86,6 @@
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
#include "src/objects/map.h"
|
||||
#include "src/objects/microtask-inl.h"
|
||||
#include "src/objects/microtask-queue-inl.h"
|
||||
#include "src/objects/module-inl.h"
|
||||
#include "src/objects/promise-inl.h"
|
||||
#include "src/objects/slots-atomic-inl.h"
|
||||
|
@ -167,7 +167,6 @@
|
||||
// - PromiseFulfillReactionJobTask
|
||||
// - PromiseRejectReactionJobTask
|
||||
// - PromiseResolveThenableJobTask
|
||||
// - MicrotaskQueue
|
||||
// - Module
|
||||
// - ModuleInfoEntry
|
||||
// - FeedbackCell
|
||||
@ -274,7 +273,6 @@ class LayoutDescriptor;
|
||||
class LookupIterator;
|
||||
class FieldType;
|
||||
class MaybeObjectSlot;
|
||||
class MicrotaskQueue;
|
||||
class Module;
|
||||
class ModuleInfoEntry;
|
||||
class ObjectHashTable;
|
||||
|
@ -197,8 +197,6 @@ enum InstanceType : uint16_t {
|
||||
PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE,
|
||||
WEAK_FACTORY_CLEANUP_JOB_TASK_TYPE, // LAST_MICROTASK_TYPE
|
||||
|
||||
MICROTASK_QUEUE_TYPE,
|
||||
|
||||
ALLOCATION_SITE_TYPE,
|
||||
EMBEDDER_DATA_ARRAY_TYPE,
|
||||
// FixedArrays.
|
||||
|
@ -1,29 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_OBJECTS_MICROTASK_QUEUE_INL_H_
|
||||
#define V8_OBJECTS_MICROTASK_QUEUE_INL_H_
|
||||
|
||||
#include "src/objects/microtask-queue.h"
|
||||
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects/smi-inl.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
#include "src/objects/object-macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
CAST_ACCESSOR(MicrotaskQueue)
|
||||
ACCESSORS2(MicrotaskQueue, queue, FixedArray, kQueueOffset)
|
||||
SMI_ACCESSORS(MicrotaskQueue, pending_microtask_count,
|
||||
kPendingMicrotaskCountOffset)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#include "src/objects/object-macros-undef.h"
|
||||
|
||||
#endif // V8_OBJECTS_MICROTASK_QUEUE_INL_H_
|
@ -1,40 +0,0 @@
|
||||
// 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 "src/objects/microtask-queue-inl.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// DCHECK requires this for taking the reference of it.
|
||||
constexpr int MicrotaskQueue::kMinimumQueueCapacity;
|
||||
|
||||
// static
|
||||
void MicrotaskQueue::EnqueueMicrotask(Isolate* isolate,
|
||||
Handle<MicrotaskQueue> microtask_queue,
|
||||
Handle<Microtask> microtask) {
|
||||
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
|
||||
void MicrotaskQueue::RunMicrotasks(Handle<MicrotaskQueue> microtask_queue) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -1,55 +0,0 @@
|
||||
// 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.
|
||||
|
||||
#ifndef V8_OBJECTS_MICROTASK_QUEUE_H_
|
||||
#define V8_OBJECTS_MICROTASK_QUEUE_H_
|
||||
|
||||
#include "src/objects.h"
|
||||
#include "src/objects/microtask.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
#include "src/objects/object-macros.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class V8_EXPORT_PRIVATE MicrotaskQueue : public Struct {
|
||||
public:
|
||||
DECL_CAST(MicrotaskQueue)
|
||||
DECL_VERIFIER(MicrotaskQueue)
|
||||
DECL_PRINTER(MicrotaskQueue)
|
||||
|
||||
// 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_ACCESSORS2(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);
|
||||
|
||||
// Runs all enqueued microtasks.
|
||||
static void RunMicrotasks(Handle<MicrotaskQueue> microtask_queue);
|
||||
|
||||
static constexpr int kMinimumQueueCapacity = 8;
|
||||
|
||||
static const int kQueueOffset = HeapObject::kHeaderSize;
|
||||
static const int kPendingMicrotaskCountOffset = kQueueOffset + kPointerSize;
|
||||
static const int kSize = kPendingMicrotaskCountOffset + kPointerSize;
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(MicrotaskQueue);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#include "src/objects/object-macros-undef.h"
|
||||
|
||||
#endif // V8_OBJECTS_MICROTASK_QUEUE_H_
|
@ -256,8 +256,6 @@ class RootVisitor;
|
||||
V(FixedArray, single_character_string_cache, SingleCharacterStringCache) \
|
||||
V(FixedArray, string_split_cache, StringSplitCache) \
|
||||
V(FixedArray, regexp_multiple_cache, RegExpMultipleCache) \
|
||||
/* Lists and dictionaries */ \
|
||||
V(MicrotaskQueue*, default_microtask_queue, DefaultMicrotaskQueue) \
|
||||
/* Indirection lists for isolate-independent builtins */ \
|
||||
V(FixedArray, builtins_constants_table, BuiltinsConstantsTable) \
|
||||
/* JS Entries */ \
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "src/api-inl.h"
|
||||
#include "src/math-random.h"
|
||||
#include "src/microtask-queue.h"
|
||||
#include "src/objects-inl.h"
|
||||
#include "src/objects/slots.h"
|
||||
|
||||
@ -43,6 +44,11 @@ void PartialSerializer::Serialize(Context* o, bool include_global_proxy) {
|
||||
// Reset math random cache to get fresh random numbers.
|
||||
MathRandom::ResetContext(context_);
|
||||
|
||||
DCHECK_EQ(
|
||||
0, reinterpret_cast<MicrotaskQueue*>(context_->microtask_queue_pointer())
|
||||
->size());
|
||||
context_->set_microtask_queue_pointer(nullptr);
|
||||
|
||||
VisitRootPointer(Root::kPartialSnapshotCache, nullptr, ObjectSlot(o));
|
||||
SerializeDeferredObjects();
|
||||
|
||||
|
@ -598,7 +598,9 @@ static void PartiallySerializeCustomContext(
|
||||
"var r = Math.random();"
|
||||
"var c = Math.sin(0) + Math.cos(0);"
|
||||
"var f = (function(a, b) { return a + b; }).bind(1, 2, 3);"
|
||||
"var s = parseInt('12345');");
|
||||
"var s = parseInt('12345');"
|
||||
"var p = 0;"
|
||||
"(async ()=>{ p = await 42; })();");
|
||||
|
||||
Vector<const uint8_t> source = ConstructSource(
|
||||
STATIC_CHAR_VECTOR("function g() { return [,"),
|
||||
@ -728,6 +730,11 @@ UNINITIALIZED_TEST(PartialSerializerCustomContext) {
|
||||
.ToLocalChecked();
|
||||
CHECK(s->Equals(v8_isolate->GetCurrentContext(), v8_str("12345"))
|
||||
.FromJust());
|
||||
v8::Local<v8::String> p = CompileRun("p")
|
||||
->ToString(v8_isolate->GetCurrentContext())
|
||||
.ToLocalChecked();
|
||||
CHECK(
|
||||
p->Equals(v8_isolate->GetCurrentContext(), v8_str("42")).FromJust());
|
||||
int a = CompileRun("a.length")
|
||||
->ToNumber(v8_isolate->GetCurrentContext())
|
||||
.ToLocalChecked()
|
||||
|
@ -183,8 +183,8 @@ v8_source_set("unittests_sources") {
|
||||
"libplatform/task-queue-unittest.cc",
|
||||
"libplatform/worker-thread-unittest.cc",
|
||||
"locked-queue-unittest.cc",
|
||||
"microtask-queue-unittest.cc",
|
||||
"object-unittest.cc",
|
||||
"objects/microtask-queue-unittest.cc",
|
||||
"parser/ast-value-unittest.cc",
|
||||
"parser/preparser-unittest.cc",
|
||||
"register-configuration-unittest.cc",
|
||||
|
175
test/unittests/microtask-queue-unittest.cc
Normal file
175
test/unittests/microtask-queue-unittest.cc
Normal file
@ -0,0 +1,175 @@
|
||||
// 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/microtask-queue.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "src/heap/factory.h"
|
||||
#include "src/visitors.h"
|
||||
#include "test/unittests/test-utils.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
using Closure = std::function<void()>;
|
||||
|
||||
void RunStdFunction(void* data) {
|
||||
std::unique_ptr<Closure> f(static_cast<Closure*>(data));
|
||||
(*f)();
|
||||
}
|
||||
|
||||
class MicrotaskQueueTest : public TestWithNativeContext {
|
||||
public:
|
||||
template <typename F>
|
||||
Handle<Microtask> NewMicrotask(F&& f) {
|
||||
Handle<Foreign> runner =
|
||||
factory()->NewForeign(reinterpret_cast<Address>(&RunStdFunction));
|
||||
Handle<Foreign> data = factory()->NewForeign(
|
||||
reinterpret_cast<Address>(new Closure(std::forward<F>(f))));
|
||||
return factory()->NewCallbackTask(runner, data);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
isolate()->default_microtask_queue()->RunMicrotasks(isolate());
|
||||
}
|
||||
};
|
||||
|
||||
class RecordingVisitor : public RootVisitor {
|
||||
public:
|
||||
RecordingVisitor() = default;
|
||||
~RecordingVisitor() override = default;
|
||||
|
||||
void VisitRootPointers(Root root, const char* description, ObjectSlot start,
|
||||
ObjectSlot end) override {
|
||||
for (ObjectSlot current = start; current != end; ++current) {
|
||||
visited_.push_back(*current);
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<Object*>& visited() const { return visited_; }
|
||||
|
||||
private:
|
||||
std::vector<Object*> visited_;
|
||||
};
|
||||
|
||||
// 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_FALSE(ran);
|
||||
ran = true;
|
||||
}));
|
||||
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());
|
||||
}
|
||||
|
||||
// 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(
|
||||
*NewMicrotask([&count] { EXPECT_EQ(0, count++); }));
|
||||
microtask_queue->RunMicrotasks(isolate());
|
||||
|
||||
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(
|
||||
*NewMicrotask([&count, i] { EXPECT_EQ(i, count++); }));
|
||||
}
|
||||
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(
|
||||
[&] { EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 1, count++); }));
|
||||
|
||||
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());
|
||||
EXPECT_EQ(MicrotaskQueue::kMinimumCapacity + 2, count);
|
||||
}
|
||||
|
||||
// MicrotaskQueue instances form a doubly linked list.
|
||||
TEST_F(MicrotaskQueueTest, InstanceChain) {
|
||||
MicrotaskQueue* default_mtq = isolate()->default_microtask_queue();
|
||||
ASSERT_TRUE(default_mtq);
|
||||
EXPECT_EQ(default_mtq, default_mtq->next());
|
||||
EXPECT_EQ(default_mtq, default_mtq->prev());
|
||||
|
||||
// Create two instances, and check their connection.
|
||||
// The list contains all instances in the creation order, and the next of the
|
||||
// last instance is the first instance:
|
||||
// default_mtq -> mtq1 -> mtq2 -> default_mtq.
|
||||
std::unique_ptr<MicrotaskQueue> mtq1 = MicrotaskQueue::New(isolate());
|
||||
std::unique_ptr<MicrotaskQueue> mtq2 = MicrotaskQueue::New(isolate());
|
||||
EXPECT_EQ(default_mtq->next(), mtq1.get());
|
||||
EXPECT_EQ(mtq1->next(), mtq2.get());
|
||||
EXPECT_EQ(mtq2->next(), default_mtq);
|
||||
EXPECT_EQ(default_mtq, mtq1->prev());
|
||||
EXPECT_EQ(mtq1.get(), mtq2->prev());
|
||||
EXPECT_EQ(mtq2.get(), default_mtq->prev());
|
||||
|
||||
// Deleted item should be also removed from the list.
|
||||
mtq1 = nullptr;
|
||||
EXPECT_EQ(default_mtq->next(), mtq2.get());
|
||||
EXPECT_EQ(mtq2->next(), default_mtq);
|
||||
EXPECT_EQ(default_mtq, mtq2->prev());
|
||||
EXPECT_EQ(mtq2.get(), default_mtq->prev());
|
||||
}
|
||||
|
||||
// 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->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);
|
||||
}
|
||||
EXPECT_GT(microtask_queue->start() + microtask_queue->size(),
|
||||
microtask_queue->capacity());
|
||||
|
||||
RecordingVisitor visitor;
|
||||
microtask_queue->IterateMicrotasks(&visitor);
|
||||
|
||||
std::vector<Object*> actual = visitor.visited();
|
||||
std::sort(expected.begin(), expected.end());
|
||||
std::sort(actual.begin(), actual.end());
|
||||
EXPECT_EQ(expected, actual);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -1,55 +0,0 @@
|
||||
// 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-inl.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 happens.
|
||||
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
|
@ -85,53 +85,52 @@ INSTANCE_TYPES = {
|
||||
181: "PROMISE_REJECT_REACTION_JOB_TASK_TYPE",
|
||||
182: "PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE",
|
||||
183: "WEAK_FACTORY_CLEANUP_JOB_TASK_TYPE",
|
||||
184: "MICROTASK_QUEUE_TYPE",
|
||||
185: "ALLOCATION_SITE_TYPE",
|
||||
186: "EMBEDDER_DATA_ARRAY_TYPE",
|
||||
187: "FIXED_ARRAY_TYPE",
|
||||
188: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE",
|
||||
189: "HASH_TABLE_TYPE",
|
||||
190: "ORDERED_HASH_MAP_TYPE",
|
||||
191: "ORDERED_HASH_SET_TYPE",
|
||||
192: "ORDERED_NAME_DICTIONARY_TYPE",
|
||||
193: "NAME_DICTIONARY_TYPE",
|
||||
194: "GLOBAL_DICTIONARY_TYPE",
|
||||
195: "NUMBER_DICTIONARY_TYPE",
|
||||
196: "SIMPLE_NUMBER_DICTIONARY_TYPE",
|
||||
197: "STRING_TABLE_TYPE",
|
||||
198: "EPHEMERON_HASH_TABLE_TYPE",
|
||||
199: "SCOPE_INFO_TYPE",
|
||||
200: "SCRIPT_CONTEXT_TABLE_TYPE",
|
||||
201: "AWAIT_CONTEXT_TYPE",
|
||||
202: "BLOCK_CONTEXT_TYPE",
|
||||
203: "CATCH_CONTEXT_TYPE",
|
||||
204: "DEBUG_EVALUATE_CONTEXT_TYPE",
|
||||
205: "EVAL_CONTEXT_TYPE",
|
||||
206: "FUNCTION_CONTEXT_TYPE",
|
||||
207: "MODULE_CONTEXT_TYPE",
|
||||
208: "NATIVE_CONTEXT_TYPE",
|
||||
209: "SCRIPT_CONTEXT_TYPE",
|
||||
210: "WITH_CONTEXT_TYPE",
|
||||
211: "WEAK_FIXED_ARRAY_TYPE",
|
||||
212: "TRANSITION_ARRAY_TYPE",
|
||||
213: "CALL_HANDLER_INFO_TYPE",
|
||||
214: "CELL_TYPE",
|
||||
215: "CODE_DATA_CONTAINER_TYPE",
|
||||
216: "DESCRIPTOR_ARRAY_TYPE",
|
||||
217: "FEEDBACK_CELL_TYPE",
|
||||
218: "FEEDBACK_VECTOR_TYPE",
|
||||
219: "LOAD_HANDLER_TYPE",
|
||||
220: "PRE_PARSED_SCOPE_DATA_TYPE",
|
||||
221: "PROPERTY_ARRAY_TYPE",
|
||||
222: "PROPERTY_CELL_TYPE",
|
||||
223: "SHARED_FUNCTION_INFO_TYPE",
|
||||
224: "SMALL_ORDERED_HASH_MAP_TYPE",
|
||||
225: "SMALL_ORDERED_HASH_SET_TYPE",
|
||||
226: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
|
||||
227: "STORE_HANDLER_TYPE",
|
||||
228: "UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE",
|
||||
229: "UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE",
|
||||
230: "WEAK_ARRAY_LIST_TYPE",
|
||||
184: "ALLOCATION_SITE_TYPE",
|
||||
185: "EMBEDDER_DATA_ARRAY_TYPE",
|
||||
186: "FIXED_ARRAY_TYPE",
|
||||
187: "OBJECT_BOILERPLATE_DESCRIPTION_TYPE",
|
||||
188: "HASH_TABLE_TYPE",
|
||||
189: "ORDERED_HASH_MAP_TYPE",
|
||||
190: "ORDERED_HASH_SET_TYPE",
|
||||
191: "ORDERED_NAME_DICTIONARY_TYPE",
|
||||
192: "NAME_DICTIONARY_TYPE",
|
||||
193: "GLOBAL_DICTIONARY_TYPE",
|
||||
194: "NUMBER_DICTIONARY_TYPE",
|
||||
195: "SIMPLE_NUMBER_DICTIONARY_TYPE",
|
||||
196: "STRING_TABLE_TYPE",
|
||||
197: "EPHEMERON_HASH_TABLE_TYPE",
|
||||
198: "SCOPE_INFO_TYPE",
|
||||
199: "SCRIPT_CONTEXT_TABLE_TYPE",
|
||||
200: "AWAIT_CONTEXT_TYPE",
|
||||
201: "BLOCK_CONTEXT_TYPE",
|
||||
202: "CATCH_CONTEXT_TYPE",
|
||||
203: "DEBUG_EVALUATE_CONTEXT_TYPE",
|
||||
204: "EVAL_CONTEXT_TYPE",
|
||||
205: "FUNCTION_CONTEXT_TYPE",
|
||||
206: "MODULE_CONTEXT_TYPE",
|
||||
207: "NATIVE_CONTEXT_TYPE",
|
||||
208: "SCRIPT_CONTEXT_TYPE",
|
||||
209: "WITH_CONTEXT_TYPE",
|
||||
210: "WEAK_FIXED_ARRAY_TYPE",
|
||||
211: "TRANSITION_ARRAY_TYPE",
|
||||
212: "CALL_HANDLER_INFO_TYPE",
|
||||
213: "CELL_TYPE",
|
||||
214: "CODE_DATA_CONTAINER_TYPE",
|
||||
215: "DESCRIPTOR_ARRAY_TYPE",
|
||||
216: "FEEDBACK_CELL_TYPE",
|
||||
217: "FEEDBACK_VECTOR_TYPE",
|
||||
218: "LOAD_HANDLER_TYPE",
|
||||
219: "PRE_PARSED_SCOPE_DATA_TYPE",
|
||||
220: "PROPERTY_ARRAY_TYPE",
|
||||
221: "PROPERTY_CELL_TYPE",
|
||||
222: "SHARED_FUNCTION_INFO_TYPE",
|
||||
223: "SMALL_ORDERED_HASH_MAP_TYPE",
|
||||
224: "SMALL_ORDERED_HASH_SET_TYPE",
|
||||
225: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
|
||||
226: "STORE_HANDLER_TYPE",
|
||||
227: "UNCOMPILED_DATA_WITHOUT_PRE_PARSED_SCOPE_TYPE",
|
||||
228: "UNCOMPILED_DATA_WITH_PRE_PARSED_SCOPE_TYPE",
|
||||
229: "WEAK_ARRAY_LIST_TYPE",
|
||||
1024: "JS_PROXY_TYPE",
|
||||
1025: "JS_GLOBAL_OBJECT_TYPE",
|
||||
1026: "JS_GLOBAL_PROXY_TYPE",
|
||||
@ -196,8 +195,8 @@ KNOWN_MAPS = {
|
||||
("RO_SPACE", 0x00139): (138, "FreeSpaceMap"),
|
||||
("RO_SPACE", 0x00189): (132, "MetaMap"),
|
||||
("RO_SPACE", 0x00209): (131, "NullMap"),
|
||||
("RO_SPACE", 0x00271): (216, "DescriptorArrayMap"),
|
||||
("RO_SPACE", 0x002d1): (211, "WeakFixedArrayMap"),
|
||||
("RO_SPACE", 0x00271): (215, "DescriptorArrayMap"),
|
||||
("RO_SPACE", 0x002d1): (210, "WeakFixedArrayMap"),
|
||||
("RO_SPACE", 0x00321): (152, "OnePointerFillerMap"),
|
||||
("RO_SPACE", 0x00371): (152, "TwoPointerFillerMap"),
|
||||
("RO_SPACE", 0x003f1): (131, "UninitializedMap"),
|
||||
@ -207,70 +206,70 @@ KNOWN_MAPS = {
|
||||
("RO_SPACE", 0x005e1): (131, "TheHoleMap"),
|
||||
("RO_SPACE", 0x00689): (131, "BooleanMap"),
|
||||
("RO_SPACE", 0x00761): (136, "ByteArrayMap"),
|
||||
("RO_SPACE", 0x007b1): (187, "FixedArrayMap"),
|
||||
("RO_SPACE", 0x00801): (187, "FixedCOWArrayMap"),
|
||||
("RO_SPACE", 0x00851): (189, "HashTableMap"),
|
||||
("RO_SPACE", 0x007b1): (186, "FixedArrayMap"),
|
||||
("RO_SPACE", 0x00801): (186, "FixedCOWArrayMap"),
|
||||
("RO_SPACE", 0x00851): (188, "HashTableMap"),
|
||||
("RO_SPACE", 0x008a1): (128, "SymbolMap"),
|
||||
("RO_SPACE", 0x008f1): (72, "OneByteStringMap"),
|
||||
("RO_SPACE", 0x00941): (199, "ScopeInfoMap"),
|
||||
("RO_SPACE", 0x00991): (223, "SharedFunctionInfoMap"),
|
||||
("RO_SPACE", 0x00941): (198, "ScopeInfoMap"),
|
||||
("RO_SPACE", 0x00991): (222, "SharedFunctionInfoMap"),
|
||||
("RO_SPACE", 0x009e1): (133, "CodeMap"),
|
||||
("RO_SPACE", 0x00a31): (206, "FunctionContextMap"),
|
||||
("RO_SPACE", 0x00a81): (214, "CellMap"),
|
||||
("RO_SPACE", 0x00ad1): (222, "GlobalPropertyCellMap"),
|
||||
("RO_SPACE", 0x00a31): (205, "FunctionContextMap"),
|
||||
("RO_SPACE", 0x00a81): (213, "CellMap"),
|
||||
("RO_SPACE", 0x00ad1): (221, "GlobalPropertyCellMap"),
|
||||
("RO_SPACE", 0x00b21): (135, "ForeignMap"),
|
||||
("RO_SPACE", 0x00b71): (212, "TransitionArrayMap"),
|
||||
("RO_SPACE", 0x00bc1): (218, "FeedbackVectorMap"),
|
||||
("RO_SPACE", 0x00b71): (211, "TransitionArrayMap"),
|
||||
("RO_SPACE", 0x00bc1): (217, "FeedbackVectorMap"),
|
||||
("RO_SPACE", 0x00c61): (131, "ArgumentsMarkerMap"),
|
||||
("RO_SPACE", 0x00d01): (131, "ExceptionMap"),
|
||||
("RO_SPACE", 0x00da1): (131, "TerminationExceptionMap"),
|
||||
("RO_SPACE", 0x00e49): (131, "OptimizedOutMap"),
|
||||
("RO_SPACE", 0x00ee9): (131, "StaleRegisterMap"),
|
||||
("RO_SPACE", 0x00f59): (208, "NativeContextMap"),
|
||||
("RO_SPACE", 0x00fa9): (207, "ModuleContextMap"),
|
||||
("RO_SPACE", 0x00ff9): (205, "EvalContextMap"),
|
||||
("RO_SPACE", 0x01049): (209, "ScriptContextMap"),
|
||||
("RO_SPACE", 0x01099): (201, "AwaitContextMap"),
|
||||
("RO_SPACE", 0x010e9): (202, "BlockContextMap"),
|
||||
("RO_SPACE", 0x01139): (203, "CatchContextMap"),
|
||||
("RO_SPACE", 0x01189): (210, "WithContextMap"),
|
||||
("RO_SPACE", 0x011d9): (204, "DebugEvaluateContextMap"),
|
||||
("RO_SPACE", 0x01229): (200, "ScriptContextTableMap"),
|
||||
("RO_SPACE", 0x00f59): (207, "NativeContextMap"),
|
||||
("RO_SPACE", 0x00fa9): (206, "ModuleContextMap"),
|
||||
("RO_SPACE", 0x00ff9): (204, "EvalContextMap"),
|
||||
("RO_SPACE", 0x01049): (208, "ScriptContextMap"),
|
||||
("RO_SPACE", 0x01099): (200, "AwaitContextMap"),
|
||||
("RO_SPACE", 0x010e9): (201, "BlockContextMap"),
|
||||
("RO_SPACE", 0x01139): (202, "CatchContextMap"),
|
||||
("RO_SPACE", 0x01189): (209, "WithContextMap"),
|
||||
("RO_SPACE", 0x011d9): (203, "DebugEvaluateContextMap"),
|
||||
("RO_SPACE", 0x01229): (199, "ScriptContextTableMap"),
|
||||
("RO_SPACE", 0x01279): (151, "FeedbackMetadataArrayMap"),
|
||||
("RO_SPACE", 0x012c9): (187, "ArrayListMap"),
|
||||
("RO_SPACE", 0x012c9): (186, "ArrayListMap"),
|
||||
("RO_SPACE", 0x01319): (130, "BigIntMap"),
|
||||
("RO_SPACE", 0x01369): (188, "ObjectBoilerplateDescriptionMap"),
|
||||
("RO_SPACE", 0x01369): (187, "ObjectBoilerplateDescriptionMap"),
|
||||
("RO_SPACE", 0x013b9): (137, "BytecodeArrayMap"),
|
||||
("RO_SPACE", 0x01409): (215, "CodeDataContainerMap"),
|
||||
("RO_SPACE", 0x01409): (214, "CodeDataContainerMap"),
|
||||
("RO_SPACE", 0x01459): (150, "FixedDoubleArrayMap"),
|
||||
("RO_SPACE", 0x014a9): (194, "GlobalDictionaryMap"),
|
||||
("RO_SPACE", 0x014f9): (217, "ManyClosuresCellMap"),
|
||||
("RO_SPACE", 0x01549): (187, "ModuleInfoMap"),
|
||||
("RO_SPACE", 0x014a9): (193, "GlobalDictionaryMap"),
|
||||
("RO_SPACE", 0x014f9): (216, "ManyClosuresCellMap"),
|
||||
("RO_SPACE", 0x01549): (186, "ModuleInfoMap"),
|
||||
("RO_SPACE", 0x01599): (134, "MutableHeapNumberMap"),
|
||||
("RO_SPACE", 0x015e9): (193, "NameDictionaryMap"),
|
||||
("RO_SPACE", 0x01639): (217, "NoClosuresCellMap"),
|
||||
("RO_SPACE", 0x01689): (217, "NoFeedbackCellMap"),
|
||||
("RO_SPACE", 0x016d9): (195, "NumberDictionaryMap"),
|
||||
("RO_SPACE", 0x01729): (217, "OneClosureCellMap"),
|
||||
("RO_SPACE", 0x01779): (190, "OrderedHashMapMap"),
|
||||
("RO_SPACE", 0x017c9): (191, "OrderedHashSetMap"),
|
||||
("RO_SPACE", 0x01819): (192, "OrderedNameDictionaryMap"),
|
||||
("RO_SPACE", 0x01869): (220, "PreParsedScopeDataMap"),
|
||||
("RO_SPACE", 0x018b9): (221, "PropertyArrayMap"),
|
||||
("RO_SPACE", 0x01909): (213, "SideEffectCallHandlerInfoMap"),
|
||||
("RO_SPACE", 0x01959): (213, "SideEffectFreeCallHandlerInfoMap"),
|
||||
("RO_SPACE", 0x019a9): (213, "NextCallSideEffectFreeCallHandlerInfoMap"),
|
||||
("RO_SPACE", 0x019f9): (196, "SimpleNumberDictionaryMap"),
|
||||
("RO_SPACE", 0x01a49): (187, "SloppyArgumentsElementsMap"),
|
||||
("RO_SPACE", 0x01a99): (224, "SmallOrderedHashMapMap"),
|
||||
("RO_SPACE", 0x01ae9): (225, "SmallOrderedHashSetMap"),
|
||||
("RO_SPACE", 0x01b39): (226, "SmallOrderedNameDictionaryMap"),
|
||||
("RO_SPACE", 0x01b89): (197, "StringTableMap"),
|
||||
("RO_SPACE", 0x01bd9): (228, "UncompiledDataWithoutPreParsedScopeMap"),
|
||||
("RO_SPACE", 0x01c29): (229, "UncompiledDataWithPreParsedScopeMap"),
|
||||
("RO_SPACE", 0x01c79): (230, "WeakArrayListMap"),
|
||||
("RO_SPACE", 0x01cc9): (198, "EphemeronHashTableMap"),
|
||||
("RO_SPACE", 0x01d19): (186, "EmbedderDataArrayMap"),
|
||||
("RO_SPACE", 0x015e9): (192, "NameDictionaryMap"),
|
||||
("RO_SPACE", 0x01639): (216, "NoClosuresCellMap"),
|
||||
("RO_SPACE", 0x01689): (216, "NoFeedbackCellMap"),
|
||||
("RO_SPACE", 0x016d9): (194, "NumberDictionaryMap"),
|
||||
("RO_SPACE", 0x01729): (216, "OneClosureCellMap"),
|
||||
("RO_SPACE", 0x01779): (189, "OrderedHashMapMap"),
|
||||
("RO_SPACE", 0x017c9): (190, "OrderedHashSetMap"),
|
||||
("RO_SPACE", 0x01819): (191, "OrderedNameDictionaryMap"),
|
||||
("RO_SPACE", 0x01869): (219, "PreParsedScopeDataMap"),
|
||||
("RO_SPACE", 0x018b9): (220, "PropertyArrayMap"),
|
||||
("RO_SPACE", 0x01909): (212, "SideEffectCallHandlerInfoMap"),
|
||||
("RO_SPACE", 0x01959): (212, "SideEffectFreeCallHandlerInfoMap"),
|
||||
("RO_SPACE", 0x019a9): (212, "NextCallSideEffectFreeCallHandlerInfoMap"),
|
||||
("RO_SPACE", 0x019f9): (195, "SimpleNumberDictionaryMap"),
|
||||
("RO_SPACE", 0x01a49): (186, "SloppyArgumentsElementsMap"),
|
||||
("RO_SPACE", 0x01a99): (223, "SmallOrderedHashMapMap"),
|
||||
("RO_SPACE", 0x01ae9): (224, "SmallOrderedHashSetMap"),
|
||||
("RO_SPACE", 0x01b39): (225, "SmallOrderedNameDictionaryMap"),
|
||||
("RO_SPACE", 0x01b89): (196, "StringTableMap"),
|
||||
("RO_SPACE", 0x01bd9): (227, "UncompiledDataWithoutPreParsedScopeMap"),
|
||||
("RO_SPACE", 0x01c29): (228, "UncompiledDataWithPreParsedScopeMap"),
|
||||
("RO_SPACE", 0x01c79): (229, "WeakArrayListMap"),
|
||||
("RO_SPACE", 0x01cc9): (197, "EphemeronHashTableMap"),
|
||||
("RO_SPACE", 0x01d19): (185, "EmbedderDataArrayMap"),
|
||||
("RO_SPACE", 0x01d69): (106, "NativeSourceStringMap"),
|
||||
("RO_SPACE", 0x01db9): (64, "StringMap"),
|
||||
("RO_SPACE", 0x01e09): (73, "ConsOneByteStringMap"),
|
||||
@ -335,16 +334,15 @@ KNOWN_MAPS = {
|
||||
("RO_SPACE", 0x058a1): (181, "PromiseRejectReactionJobTaskMap"),
|
||||
("RO_SPACE", 0x058f1): (182, "PromiseResolveThenableJobTaskMap"),
|
||||
("RO_SPACE", 0x05941): (183, "WeakFactoryCleanupJobTaskMap"),
|
||||
("RO_SPACE", 0x05991): (184, "MicrotaskQueueMap"),
|
||||
("RO_SPACE", 0x059e1): (185, "AllocationSiteWithWeakNextMap"),
|
||||
("RO_SPACE", 0x05a31): (185, "AllocationSiteWithoutWeakNextMap"),
|
||||
("RO_SPACE", 0x05a81): (219, "LoadHandler1Map"),
|
||||
("RO_SPACE", 0x05ad1): (219, "LoadHandler2Map"),
|
||||
("RO_SPACE", 0x05b21): (219, "LoadHandler3Map"),
|
||||
("RO_SPACE", 0x05b71): (227, "StoreHandler0Map"),
|
||||
("RO_SPACE", 0x05bc1): (227, "StoreHandler1Map"),
|
||||
("RO_SPACE", 0x05c11): (227, "StoreHandler2Map"),
|
||||
("RO_SPACE", 0x05c61): (227, "StoreHandler3Map"),
|
||||
("RO_SPACE", 0x05991): (184, "AllocationSiteWithWeakNextMap"),
|
||||
("RO_SPACE", 0x059e1): (184, "AllocationSiteWithoutWeakNextMap"),
|
||||
("RO_SPACE", 0x05a31): (218, "LoadHandler1Map"),
|
||||
("RO_SPACE", 0x05a81): (218, "LoadHandler2Map"),
|
||||
("RO_SPACE", 0x05ad1): (218, "LoadHandler3Map"),
|
||||
("RO_SPACE", 0x05b21): (226, "StoreHandler0Map"),
|
||||
("RO_SPACE", 0x05b71): (226, "StoreHandler1Map"),
|
||||
("RO_SPACE", 0x05bc1): (226, "StoreHandler2Map"),
|
||||
("RO_SPACE", 0x05c11): (226, "StoreHandler3Map"),
|
||||
("MAP_SPACE", 0x00139): (1057, "ExternalMap"),
|
||||
("MAP_SPACE", 0x00189): (1073, "JSMessageObjectMap"),
|
||||
}
|
||||
@ -434,8 +432,7 @@ KNOWN_OBJECTS = {
|
||||
("OLD_SPACE", 0x008d9): "SingleCharacterStringCache",
|
||||
("OLD_SPACE", 0x010e9): "StringSplitCache",
|
||||
("OLD_SPACE", 0x018f9): "RegExpMultipleCache",
|
||||
("OLD_SPACE", 0x02109): "DefaultMicrotaskQueue",
|
||||
("OLD_SPACE", 0x02121): "BuiltinsConstantsTable",
|
||||
("OLD_SPACE", 0x02109): "BuiltinsConstantsTable",
|
||||
}
|
||||
|
||||
# List of known V8 Frame Markers.
|
||||
|
Loading…
Reference in New Issue
Block a user