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:
Yang Guo 2018-11-27 09:32:53 +01:00 committed by Commit Bot
parent ca39f55ae1
commit 3a437ce47a
33 changed files with 714 additions and 497 deletions

View File

@ -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",

View File

@ -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.

View File

@ -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());

View File

@ -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);

View File

@ -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:

View File

@ -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) \

View File

@ -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));
}

View File

@ -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") \

View File

@ -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);

View File

@ -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);

View File

@ -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"

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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
View 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
View 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_

View File

@ -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());

View File

@ -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)

View File

@ -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());

View File

@ -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"

View File

@ -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;

View File

@ -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.

View File

@ -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_

View File

@ -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

View File

@ -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_

View File

@ -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 */ \

View File

@ -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();

View File

@ -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()

View File

@ -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",

View 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

View File

@ -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

View File

@ -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.