[compiler-dispatcher] Move Job pointer to SFI

Reduce the enqueuing cost of compiler-dispatcher jobs by getting rid of
the sets and hashmaps, and instead:

  1. Turning the pending job set into a queue, and
  2. Making the SharedFunctionInfo's UncompiledData hold a pointer to
     the LazyCompilerDispatcher::Job, instead of maintaining an
     IdentityMap from one to the other.

To avoid bloating all UncompiledData, this adds two new UncompiledData
subclasses, making it four subclasses total, for with/without Preparse
data and with/without a Job pointer. "should_parallel_compile"
FunctionLiterals get allocated an UncompiledData with a job pointer by
default, otherwise enqueueing a SFI without a job pointer triggers a
reallocation of the UncompiledData to add a job pointer.

Since there is no longer a set of all Jobs (aside from one for
debug-only), we need to be careful to manually clear the Job pointer
from the UncompiledData whenever we finish a Job (whether successfully
or by aborting) and we have to make sure that we implicitly can reach
all Jobs via the pending/finalizable lists, or the set of currently
running jobs.

Change-Id: I3aae78e6dfbdc74f5f7c1411de398433907b2705
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3314833
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78302}
This commit is contained in:
Leszek Swirski 2021-12-08 16:03:09 +01:00 committed by V8 LUCI CQ
parent 657e5dc1d9
commit 3b9091c827
16 changed files with 611 additions and 239 deletions

View File

@ -14458,6 +14458,8 @@ TNode<CodeT> CodeStubAssembler::GetSharedFunctionInfoCode(
CODET_TYPE,
UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE,
UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE,
UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE,
UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE,
FUNCTION_TEMPLATE_INFO_TYPE,
#if V8_ENABLE_WEBASSEMBLY
WASM_CAPI_FUNCTION_DATA_TYPE,
@ -14469,16 +14471,17 @@ TNode<CodeT> CodeStubAssembler::GetSharedFunctionInfoCode(
Label check_is_bytecode_array(this);
Label check_is_baseline_data(this);
Label check_is_asm_wasm_data(this);
Label check_is_uncompiled_data_without_preparse_data(this);
Label check_is_uncompiled_data_with_preparse_data(this);
Label check_is_uncompiled_data(this);
Label check_is_function_template_info(this);
Label check_is_interpreter_data(this);
Label check_is_wasm_function_data(this);
Label* case_labels[] = {
&check_is_bytecode_array,
&check_is_baseline_data,
&check_is_uncompiled_data_without_preparse_data,
&check_is_uncompiled_data_with_preparse_data,
&check_is_uncompiled_data,
&check_is_uncompiled_data,
&check_is_uncompiled_data,
&check_is_uncompiled_data,
&check_is_function_template_info,
#if V8_ENABLE_WEBASSEMBLY
&check_is_wasm_function_data,
@ -14506,9 +14509,7 @@ TNode<CodeT> CodeStubAssembler::GetSharedFunctionInfoCode(
// IsUncompiledDataWithPreparseData | IsUncompiledDataWithoutPreparseData:
// Compile lazy
BIND(&check_is_uncompiled_data_with_preparse_data);
Goto(&check_is_uncompiled_data_without_preparse_data);
BIND(&check_is_uncompiled_data_without_preparse_data);
BIND(&check_is_uncompiled_data);
sfi_code = HeapConstant(BUILTIN_CODET(isolate(), CompileLazy));
Goto(if_compile_lazy ? if_compile_lazy : &done);

View File

@ -1648,6 +1648,12 @@ bool BackgroundCompileTask::FinalizeFunction(
Handle<SharedFunctionInfo> input_shared_info =
input_shared_info_.ToHandleChecked();
// The UncompiledData on the input SharedFunctionInfo will have a pointer to
// the LazyCompileDispatcher Job that launched this task, which will now be
// considered complete, so clear that regardless of whether the finalize
// succeeds or not.
input_shared_info->ClearUncompiledDataJobPointer();
// We might not have been able to finalize all jobs on the background
// thread (e.g. asm.js jobs), so finalize those deferred jobs now.
if (FinalizeDeferredUnoptimizedCompilationJobs(
@ -1675,6 +1681,14 @@ bool BackgroundCompileTask::FinalizeFunction(
return true;
}
void BackgroundCompileTask::AbortFunction() {
// The UncompiledData on the input SharedFunctionInfo will have a pointer to
// the LazyCompileDispatcher Job that launched this task, which is about to be
// deleted, so clear that to avoid the SharedFunctionInfo from pointing to
// deallocated memory.
input_shared_info_.ToHandleChecked()->ClearUncompiledDataJobPointer();
}
void BackgroundCompileTask::ReportStatistics(Isolate* isolate) {
// Update use-counts.
for (int i = 0; i < static_cast<int>(v8::Isolate::kUseCounterFeatureCount);

View File

@ -525,12 +525,16 @@ class V8_EXPORT_PRIVATE BackgroundCompileTask {
bool FinalizeFunction(Isolate* isolate, Compiler::ClearExceptionFlag flag);
void AbortFunction();
UnoptimizedCompileFlags flags() const { return flags_; }
LanguageMode language_mode() const { return language_mode_; }
private:
void ReportStatistics(Isolate* isolate);
void ClearFunctionJobPointer();
// Data needed for parsing and compilation. These need to be initialized
// before the compilation starts.
Isolate* isolate_for_local_isolate_;

View File

@ -11,16 +11,19 @@
#include "src/base/platform/mutex.h"
#include "src/base/platform/time.h"
#include "src/codegen/compiler.h"
#include "src/common/globals.h"
#include "src/flags/flags.h"
#include "src/handles/global-handles-inl.h"
#include "src/heap/parked-scope.h"
#include "src/logging/counters.h"
#include "src/logging/runtime-call-stats-scope.h"
#include "src/numbers/hash-seed-inl.h"
#include "src/objects/instance-type.h"
#include "src/objects/objects-inl.h"
#include "src/parsing/parse-info.h"
#include "src/parsing/parser.h"
#include "src/roots/roots.h"
#include "src/security/external-pointer.h"
#include "src/tasks/cancelable-task.h"
#include "src/tasks/task-utils.h"
#include "src/zone/zone-list-inl.h" // crbug.com/v8/8816
@ -72,7 +75,6 @@ LazyCompileDispatcher::LazyCompileDispatcher(Isolate* isolate,
max_stack_size_(max_stack_size),
trace_compiler_dispatcher_(FLAG_trace_compiler_dispatcher),
idle_task_manager_(new CancelableTaskManager()),
shared_to_unoptimized_job_(isolate->heap()),
idle_task_scheduled_(false),
num_jobs_for_background_(0),
main_thread_blocking_on_job_(nullptr),
@ -87,6 +89,65 @@ LazyCompileDispatcher::~LazyCompileDispatcher() {
CHECK(!job_handle_->IsValid());
}
namespace {
// If the SharedFunctionInfo's UncompiledData has a job slot, then write into
// it. Otherwise, allocate a new UncompiledData with a job slot, and then write
// into that. Since we have two optional slots (preparse data and job), this
// gets a little messy.
void SetUncompiledDataJobPointer(LocalIsolate* isolate,
Handle<SharedFunctionInfo> shared_info,
Address job_address) {
UncompiledData uncompiled_data = shared_info->uncompiled_data();
switch (uncompiled_data.map(isolate).instance_type()) {
// The easy cases -- we already have a job slot, so can write into it and
// return.
case UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE:
UncompiledDataWithPreparseDataAndJob::cast(uncompiled_data)
.set_job(job_address);
break;
case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE:
UncompiledDataWithoutPreparseDataWithJob::cast(uncompiled_data)
.set_job(job_address);
break;
// Otherwise, we'll have to allocate a new UncompiledData (with or without
// preparse data as appropriate), set the job pointer on that, and update
// the SharedFunctionInfo to use the new UncompiledData
case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE: {
Handle<String> inferred_name(uncompiled_data.inferred_name(), isolate);
Handle<PreparseData> preparse_data(
UncompiledDataWithPreparseData::cast(uncompiled_data).preparse_data(),
isolate);
Handle<UncompiledDataWithPreparseDataAndJob> new_uncompiled_data =
isolate->factory()->NewUncompiledDataWithPreparseDataAndJob(
inferred_name, uncompiled_data.start_position(),
uncompiled_data.end_position(), preparse_data);
new_uncompiled_data->set_job(job_address);
shared_info->set_uncompiled_data(*new_uncompiled_data);
break;
}
case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE: {
DCHECK(uncompiled_data.IsUncompiledDataWithoutPreparseData());
Handle<String> inferred_name(uncompiled_data.inferred_name(), isolate);
Handle<UncompiledDataWithoutPreparseDataWithJob> new_uncompiled_data =
isolate->factory()->NewUncompiledDataWithoutPreparseDataWithJob(
inferred_name, uncompiled_data.start_position(),
uncompiled_data.end_position());
new_uncompiled_data->set_job(job_address);
shared_info->set_uncompiled_data(*new_uncompiled_data);
break;
}
default:
UNREACHABLE();
}
}
} // namespace
void LazyCompileDispatcher::Enqueue(
LocalIsolate* isolate, Handle<SharedFunctionInfo> shared_info,
std::unique_ptr<Utf16CharacterStream> character_stream) {
@ -94,11 +155,13 @@ void LazyCompileDispatcher::Enqueue(
"V8.LazyCompilerDispatcherEnqueue");
RCS_SCOPE(isolate, RuntimeCallCounterId::kCompileEnqueueOnDispatcher);
std::unique_ptr<Job> job =
std::make_unique<Job>(std::make_unique<BackgroundCompileTask>(
isolate_, shared_info, std::move(character_stream),
worker_thread_runtime_call_stats_, background_compile_timer_,
static_cast<int>(max_stack_size_)));
Job* job = new Job(std::make_unique<BackgroundCompileTask>(
isolate_, shared_info, std::move(character_stream),
worker_thread_runtime_call_stats_, background_compile_timer_,
static_cast<int>(max_stack_size_)));
SetUncompiledDataJobPointer(isolate, shared_info,
reinterpret_cast<Address>(job));
// Post a a background worker task to perform the compilation on the worker
// thread.
@ -110,20 +173,28 @@ void LazyCompileDispatcher::Enqueue(
PrintF("\n");
}
pending_background_jobs_.insert(job.get());
// Transfer ownership of the job to the IdentityMap
shared_to_unoptimized_job_.Insert(shared_info, job.release());
num_jobs_for_background_ += 1;
VerifyBackgroundTaskCount(lock);
#ifdef DEBUG
all_jobs_.insert(job);
#endif
pending_background_jobs_.push_back(job);
NotifyAddedBackgroundJob(lock);
}
// This is not in NotifyAddedBackgroundJob to avoid being inside the mutex.
job_handle_->NotifyConcurrencyIncrease();
}
bool LazyCompileDispatcher::IsEnqueued(
Handle<SharedFunctionInfo> function) const {
base::MutexGuard lock(&mutex_);
return shared_to_unoptimized_job_.Find(function) != nullptr;
Job* job = nullptr;
Object function_data = function->function_data(kAcquireLoad);
if (function_data.IsUncompiledDataWithPreparseDataAndJob()) {
job = reinterpret_cast<Job*>(
UncompiledDataWithPreparseDataAndJob::cast(function_data).job());
} else if (function_data.IsUncompiledDataWithoutPreparseDataWithJob()) {
job = reinterpret_cast<Job*>(
UncompiledDataWithoutPreparseDataWithJob::cast(function_data).job());
}
return job != nullptr;
}
void LazyCompileDispatcher::WaitForJobIfRunningOnBackground(
@ -133,13 +204,30 @@ void LazyCompileDispatcher::WaitForJobIfRunningOnBackground(
RCS_SCOPE(isolate_, RuntimeCallCounterId::kCompileWaitForDispatcher);
if (!job->is_running_on_background()) {
num_jobs_for_background_ -= pending_background_jobs_.erase(job);
if (job->state == Job::State::kPending) {
DCHECK_EQ(std::count(pending_background_jobs_.begin(),
pending_background_jobs_.end(), job),
1);
// TODO(leszeks): Remove from pending jobs without walking the whole
// vector.
pending_background_jobs_.erase(
std::remove(pending_background_jobs_.begin(),
pending_background_jobs_.end(), job));
job->state = Job::State::kPendingToRunOnForeground;
NotifyRemovedBackgroundJob(lock);
} else {
DCHECK_EQ(job->state, Job::State::kReadyToFinalize);
DCHECK_EQ(
std::count(finalizable_jobs_.begin(), finalizable_jobs_.end(), job),
1);
// TODO(leszeks): Remove from finalizable jobs without walking the whole
// vector.
finalizable_jobs_.erase(
std::remove(finalizable_jobs_.begin(), finalizable_jobs_.end(), job));
job->state = Job::State::kFinalizingNow;
}
VerifyBackgroundTaskCount(lock);
return;
}
DCHECK_NULL(main_thread_blocking_on_job_);
@ -147,7 +235,16 @@ void LazyCompileDispatcher::WaitForJobIfRunningOnBackground(
while (main_thread_blocking_on_job_ != nullptr) {
main_thread_blocking_signal_.Wait(&mutex_);
}
DCHECK(pending_background_jobs_.find(job) == pending_background_jobs_.end());
DCHECK_EQ(job->state, Job::State::kReadyToFinalize);
DCHECK_EQ(std::count(finalizable_jobs_.begin(), finalizable_jobs_.end(), job),
1);
// TODO(leszeks): Remove from finalizable jobs without walking the whole
// vector.
finalizable_jobs_.erase(
std::remove(finalizable_jobs_.begin(), finalizable_jobs_.end(), job));
job->state = Job::State::kFinalizingNow;
}
bool LazyCompileDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
@ -166,20 +263,29 @@ bool LazyCompileDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
base::MutexGuard lock(&mutex_);
job = GetJobFor(function, lock);
WaitForJobIfRunningOnBackground(job, lock);
shared_to_unoptimized_job_.Delete(function, &job);
}
if (job->state == Job::State::kPendingToRunOnForeground) {
job->task->Run();
job->state = Job::State::kReadyToFinalize;
job->state = Job::State::kFinalizingNow;
}
if (DEBUG_BOOL) {
base::MutexGuard lock(&mutex_);
DCHECK_EQ(std::count(pending_background_jobs_.begin(),
pending_background_jobs_.end(), job),
0);
DCHECK_EQ(
std::count(finalizable_jobs_.begin(), finalizable_jobs_.end(), job), 0);
DCHECK_EQ(job->state, Job::State::kFinalizingNow);
}
DCHECK_EQ(job->state, Job::State::kReadyToFinalize);
bool success = Compiler::FinalizeBackgroundCompileTask(
job->task.get(), isolate_, Compiler::KEEP_EXCEPTION);
job->state = Job::State::kFinalized;
DCHECK_NE(success, isolate_->has_pending_exception());
delete job;
DeleteJob(job);
// Opportunistically finalize all other jobs for a maximum time of
// kMaxOpportunisticFinalizeTimeMs.
@ -201,16 +307,36 @@ void LazyCompileDispatcher::AbortJob(Handle<SharedFunctionInfo> shared_info) {
base::LockGuard<base::Mutex> lock(&mutex_);
Job* job = GetJobFor(shared_info, lock);
num_jobs_for_background_ -= pending_background_jobs_.erase(job);
if (job->is_running_on_background()) {
// Job is currently running on the background thread, wait until it's done
// and remove job then.
job->state = Job::State::kAbortRequested;
} else {
shared_to_unoptimized_job_.Delete(shared_info, &job);
delete job;
if (job->state == Job::State::kPending) {
DCHECK_EQ(std::count(pending_background_jobs_.begin(),
pending_background_jobs_.end(), job),
1);
pending_background_jobs_.erase(
std::remove(pending_background_jobs_.begin(),
pending_background_jobs_.end(), job));
job->state = Job::State::kAbortingNow;
NotifyRemovedBackgroundJob(lock);
} else if (job->state == Job::State::kReadyToFinalize) {
DCHECK_EQ(
std::count(finalizable_jobs_.begin(), finalizable_jobs_.end(), job),
1);
finalizable_jobs_.erase(
std::remove(finalizable_jobs_.begin(), finalizable_jobs_.end(), job));
job->state = Job::State::kAbortingNow;
} else {
UNREACHABLE();
}
job->task->AbortFunction();
job->state = Job::State::kFinalized;
DeleteJob(job, lock);
}
VerifyBackgroundTaskCount(lock);
}
void LazyCompileDispatcher::AbortAll() {
@ -219,30 +345,38 @@ void LazyCompileDispatcher::AbortAll() {
{
base::MutexGuard lock(&mutex_);
for (Job* job : pending_background_jobs_) {
job->task->AbortFunction();
job->state = Job::State::kFinalized;
DeleteJob(job, lock);
}
pending_background_jobs_.clear();
for (Job* job : finalizable_jobs_) {
job->task->AbortFunction();
job->state = Job::State::kFinalized;
DeleteJob(job, lock);
}
finalizable_jobs_.clear();
DCHECK_EQ(all_jobs_.size(), 0);
num_jobs_for_background_ = 0;
VerifyBackgroundTaskCount(lock);
}
idle_task_manager_->CancelAndWait();
{
base::MutexGuard lock(&mutex_);
{
SharedToJobMap::IteratableScope iteratable_scope(
&shared_to_unoptimized_job_);
for (Job** job_entry : iteratable_scope) {
Job* job = *job_entry;
DCHECK_NE(job->state, Job::State::kRunning);
DCHECK_NE(job->state, Job::State::kAbortRequested);
delete job;
}
}
shared_to_unoptimized_job_.Clear();
}
}
LazyCompileDispatcher::Job* LazyCompileDispatcher::GetJobFor(
Handle<SharedFunctionInfo> shared, const base::MutexGuard&) const {
return *shared_to_unoptimized_job_.Find(shared);
Object function_data = shared->function_data(kAcquireLoad);
if (function_data.IsUncompiledDataWithPreparseDataAndJob()) {
return reinterpret_cast<Job*>(
UncompiledDataWithPreparseDataAndJob::cast(function_data).job());
} else if (function_data.IsUncompiledDataWithoutPreparseDataWithJob()) {
return reinterpret_cast<Job*>(
UncompiledDataWithoutPreparseDataWithJob::cast(function_data).job());
}
return nullptr;
}
void LazyCompileDispatcher::ScheduleIdleTaskFromAnyThread(
@ -276,13 +410,13 @@ void LazyCompileDispatcher::DoBackgroundWork(JobDelegate* delegate) {
Job* job = nullptr;
{
base::MutexGuard lock(&mutex_);
if (pending_background_jobs_.empty()) break;
auto it = pending_background_jobs_.begin();
job = *it;
pending_background_jobs_.erase(it);
if (pending_background_jobs_.empty()) return;
job = pending_background_jobs_.back();
pending_background_jobs_.pop_back();
DCHECK_EQ(job->state, Job::State::kPending);
job->state = Job::State::kRunning;
VerifyBackgroundTaskCount(lock);
}
if (V8_UNLIKELY(block_for_testing_.Value())) {
@ -306,8 +440,8 @@ void LazyCompileDispatcher::DoBackgroundWork(JobDelegate* delegate) {
DCHECK_EQ(job->state, Job::State::kAbortRequested);
job->state = Job::State::kAborted;
}
num_jobs_for_background_--;
VerifyBackgroundTaskCount(lock);
finalizable_jobs_.push_back(job);
NotifyRemovedBackgroundJob(lock);
if (main_thread_blocking_on_job_ == job) {
main_thread_blocking_on_job_ = nullptr;
@ -322,50 +456,42 @@ void LazyCompileDispatcher::DoBackgroundWork(JobDelegate* delegate) {
// deleted.
}
std::tuple<SharedFunctionInfo, LazyCompileDispatcher::Job*>
LazyCompileDispatcher::GetSingleFinalizableJob(const base::MutexGuard&) {
SharedToJobMap::IteratableScope iteratable_scope(&shared_to_unoptimized_job_);
LazyCompileDispatcher::Job* LazyCompileDispatcher::PopSingleFinalizeJob() {
base::MutexGuard lock(&mutex_);
auto it = iteratable_scope.begin();
auto end = iteratable_scope.end();
for (; it != end; ++it) {
Job* job = *it.entry();
if (job->state == Job::State::kReadyToFinalize ||
job->state == Job::State::kAborted) {
return {SharedFunctionInfo::cast(it.key()), job};
}
if (finalizable_jobs_.empty()) return nullptr;
Job* job = finalizable_jobs_.back();
finalizable_jobs_.pop_back();
DCHECK(job->state == Job::State::kReadyToFinalize ||
job->state == Job::State::kAborted);
if (job->state == Job::State::kReadyToFinalize) {
job->state = Job::State::kFinalizingNow;
} else {
DCHECK_EQ(job->state, Job::State::kAborted);
job->state = Job::State::kAbortingNow;
}
// Since we hold the lock here, we can be sure no jobs have become ready
// for finalization while we looped through the list.
return {SharedFunctionInfo(), nullptr};
return job;
}
bool LazyCompileDispatcher::FinalizeSingleJob() {
SharedFunctionInfo function;
Job* job;
{
base::MutexGuard lock(&mutex_);
std::tie(function, job) = GetSingleFinalizableJob(lock);
if (job == nullptr) return false;
// We're finalizing this job now, so remove it from the map.
shared_to_unoptimized_job_.Delete(function, &job);
}
Job* job = PopSingleFinalizeJob();
if (job == nullptr) return false;
if (trace_compiler_dispatcher_) {
PrintF("LazyCompileDispatcher: idle finalizing job for ");
function.ShortPrint();
PrintF("\n");
PrintF("LazyCompileDispatcher: idle finalizing job\n");
}
if (job->state == Job::State::kReadyToFinalize) {
if (job->state == Job::State::kFinalizingNow) {
HandleScope scope(isolate_);
Compiler::FinalizeBackgroundCompileTask(job->task.get(), isolate_,
Compiler::CLEAR_EXCEPTION);
} else {
DCHECK_EQ(job->state, Job::State::kAborted);
DCHECK_EQ(job->state, Job::State::kAbortingNow);
job->task->AbortFunction();
}
delete job;
job->state = Job::State::kFinalized;
DeleteJob(job);
return true;
}
@ -395,26 +521,56 @@ void LazyCompileDispatcher::DoIdleWork(double deadline_in_seconds) {
}
}
void LazyCompileDispatcher::DeleteJob(Job* job) {
DCHECK(job->state == Job::State::kFinalized);
#ifdef DEBUG
{
base::MutexGuard lock(&mutex_);
all_jobs_.erase(job);
}
#endif
delete job;
}
void LazyCompileDispatcher::DeleteJob(Job* job, const base::MutexGuard&) {
DCHECK(job->state == Job::State::kFinalized);
#ifdef DEBUG
all_jobs_.erase(job);
#endif
delete job;
}
#ifdef DEBUG
void LazyCompileDispatcher::VerifyBackgroundTaskCount(const base::MutexGuard&) {
int running_jobs = 0;
int pending_jobs = 0;
size_t pending_jobs = 0;
size_t running_jobs = 0;
size_t finalizable_jobs = 0;
SharedToJobMap::IteratableScope iteratable_scope(&shared_to_unoptimized_job_);
auto it = iteratable_scope.begin();
auto end = iteratable_scope.end();
for (; it != end; ++it) {
Job* job = *it.entry();
if (job->state == Job::State::kRunning ||
job->state == Job::State::kAbortRequested) {
running_jobs++;
} else if (job->state == Job::State::kPending) {
pending_jobs++;
for (Job* job : all_jobs_) {
switch (job->state) {
case Job::State::kPending:
pending_jobs++;
break;
case Job::State::kRunning:
case Job::State::kAbortRequested:
running_jobs++;
break;
case Job::State::kReadyToFinalize:
case Job::State::kAborted:
finalizable_jobs++;
break;
case Job::State::kPendingToRunOnForeground:
case Job::State::kFinalizingNow:
case Job::State::kAbortingNow:
case Job::State::kFinalized:
// Ignore.
break;
}
}
CHECK_EQ(pending_jobs, pending_background_jobs_.size());
CHECK_EQ(num_jobs_for_background_.load(), running_jobs + pending_jobs);
CHECK_EQ(pending_background_jobs_.size(), pending_jobs);
CHECK_EQ(finalizable_jobs_.size(), finalizable_jobs);
CHECK_EQ(num_jobs_for_background_.load(), pending_jobs + running_jobs);
}
#endif

View File

@ -115,13 +115,29 @@ class V8_EXPORT_PRIVATE LazyCompileDispatcher {
struct Job {
enum class State {
// Background thread states (Enqueue + DoBackgroundWork)
// ---
// In the pending task queue.
kPending,
// Currently running on a background thread.
kRunning,
kAbortRequested, // ... but we want to drop the result.
// In the finalizable task queue.
kReadyToFinalize,
kFinalized,
kAbortRequested,
kAborted,
kPendingToRunOnForeground
// Main thread states (FinishNow and FinalizeSingleJob)
// ---
// Popped off the pending task queue.
kPendingToRunOnForeground,
// Popped off the finalizable task queue.
kFinalizingNow,
kAbortingNow, // ... and we want to abort
// Finished finalizing, ready for deletion.
kFinalized,
};
explicit Job(std::unique_ptr<BackgroundCompileTask> task);
@ -140,13 +156,26 @@ class V8_EXPORT_PRIVATE LazyCompileDispatcher {
void WaitForJobIfRunningOnBackground(Job* job, const base::MutexGuard&);
Job* GetJobFor(Handle<SharedFunctionInfo> shared,
const base::MutexGuard&) const;
std::tuple<SharedFunctionInfo, Job*> GetSingleFinalizableJob(
const base::MutexGuard&);
Job* PopSingleFinalizeJob();
void ScheduleIdleTaskFromAnyThread(const base::MutexGuard&);
bool FinalizeSingleJob();
void DoBackgroundWork(JobDelegate* delegate);
void DoIdleWork(double deadline_in_seconds);
// DeleteJob without the mutex held.
void DeleteJob(Job* job);
// DeleteJob with the mutex already held.
void DeleteJob(Job* job, const base::MutexGuard&);
void NotifyAddedBackgroundJob(const base::MutexGuard& lock) {
++num_jobs_for_background_;
VerifyBackgroundTaskCount(lock);
}
void NotifyRemovedBackgroundJob(const base::MutexGuard& lock) {
--num_jobs_for_background_;
VerifyBackgroundTaskCount(lock);
}
#ifdef DEBUG
void VerifyBackgroundTaskCount(const base::MutexGuard&);
#else
@ -171,20 +200,25 @@ class V8_EXPORT_PRIVATE LazyCompileDispatcher {
// the mutex |mutex_| while accessing them.
mutable base::Mutex mutex_;
// Mapping from SharedFunctionInfo to the corresponding unoptimized
// compilation job.
SharedToJobMap shared_to_unoptimized_job_;
// True if an idle task is scheduled to be run.
bool idle_task_scheduled_;
// The set of jobs that can be run on a background thread.
std::unordered_set<Job*> pending_background_jobs_;
std::vector<Job*> pending_background_jobs_;
// The set of jobs that can be finalized on the main thread.
std::vector<Job*> finalizable_jobs_;
// The total number of jobs ready to execute on background, both those pending
// and those currently running.
std::atomic<size_t> num_jobs_for_background_;
#ifdef DEBUG
// The set of all allocated jobs, used for verification of the various queues
// and counts.
std::unordered_set<Job*> all_jobs_;
#endif
// If not nullptr, then the main thread waits for the task processing
// this job, and blocks on the ConditionVariable main_thread_blocking_signal_.
Job* main_thread_blocking_on_job_;

View File

@ -357,6 +357,29 @@ FactoryBase<Impl>::NewUncompiledDataWithPreparseData(
AllocationType::kOld);
}
template <typename Impl>
Handle<UncompiledDataWithoutPreparseDataWithJob>
FactoryBase<Impl>::NewUncompiledDataWithoutPreparseDataWithJob(
Handle<String> inferred_name, int32_t start_position,
int32_t end_position) {
return TorqueGeneratedFactory<
Impl>::NewUncompiledDataWithoutPreparseDataWithJob(inferred_name,
start_position,
end_position,
kNullAddress,
AllocationType::kOld);
}
template <typename Impl>
Handle<UncompiledDataWithPreparseDataAndJob>
FactoryBase<Impl>::NewUncompiledDataWithPreparseDataAndJob(
Handle<String> inferred_name, int32_t start_position, int32_t end_position,
Handle<PreparseData> preparse_data) {
return TorqueGeneratedFactory<Impl>::NewUncompiledDataWithPreparseDataAndJob(
inferred_name, start_position, end_position, preparse_data, kNullAddress,
AllocationType::kOld);
}
template <typename Impl>
Handle<SharedFunctionInfo> FactoryBase<Impl>::NewSharedFunctionInfo(
MaybeHandle<String> maybe_name, MaybeHandle<HeapObject> maybe_function_data,

View File

@ -178,6 +178,17 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase
Handle<String> inferred_name, int32_t start_position,
int32_t end_position, Handle<PreparseData>);
Handle<UncompiledDataWithoutPreparseDataWithJob>
NewUncompiledDataWithoutPreparseDataWithJob(Handle<String> inferred_name,
int32_t start_position,
int32_t end_position);
Handle<UncompiledDataWithPreparseDataAndJob>
NewUncompiledDataWithPreparseDataAndJob(Handle<String> inferred_name,
int32_t start_position,
int32_t end_position,
Handle<PreparseData>);
// Allocates a FeedbackMedata object and zeroes the data section.
Handle<FeedbackMetadata> NewFeedbackMetadata(
int slot_count, int create_closure_slot_count,

View File

@ -230,6 +230,8 @@ class ZoneForwardList;
V(UncompiledData) \
V(UncompiledDataWithPreparseData) \
V(UncompiledDataWithoutPreparseData) \
V(UncompiledDataWithPreparseDataAndJob) \
V(UncompiledDataWithoutPreparseDataWithJob) \
V(Undetectable) \
V(UniqueName) \
IF_WASM(V, WasmApiFunctionRef) \

View File

@ -7,6 +7,7 @@
#include "src/base/macros.h"
#include "src/base/platform/mutex.h"
#include "src/codegen/optimized-compilation-info.h"
#include "src/common/globals.h"
#include "src/handles/handles-inl.h"
#include "src/heap/heap-write-barrier-inl.h"
@ -92,6 +93,8 @@ void PreparseData::set_child(int index, PreparseData value,
TQ_OBJECT_CONSTRUCTORS_IMPL(UncompiledData)
TQ_OBJECT_CONSTRUCTORS_IMPL(UncompiledDataWithoutPreparseData)
TQ_OBJECT_CONSTRUCTORS_IMPL(UncompiledDataWithPreparseData)
TQ_OBJECT_CONSTRUCTORS_IMPL(UncompiledDataWithoutPreparseDataWithJob)
TQ_OBJECT_CONSTRUCTORS_IMPL(UncompiledDataWithPreparseDataAndJob)
TQ_OBJECT_CONSTRUCTORS_IMPL(InterpreterData)
TQ_OBJECT_CONSTRUCTORS_IMPL(SharedFunctionInfo)
@ -791,6 +794,17 @@ bool SharedFunctionInfo::HasUncompiledDataWithoutPreparseData() const {
return function_data(kAcquireLoad).IsUncompiledDataWithoutPreparseData();
}
void SharedFunctionInfo::ClearUncompiledDataJobPointer() {
UncompiledData uncompiled_data = this->uncompiled_data();
if (uncompiled_data.IsUncompiledDataWithPreparseDataAndJob()) {
UncompiledDataWithPreparseDataAndJob::cast(uncompiled_data)
.set_job(kNullAddress);
} else if (uncompiled_data.IsUncompiledDataWithoutPreparseDataWithJob()) {
UncompiledDataWithoutPreparseDataWithJob::cast(uncompiled_data)
.set_job(kNullAddress);
}
}
void SharedFunctionInfo::ClearPreparseData() {
DCHECK(HasUncompiledDataWithPreparseData());
UncompiledDataWithPreparseData data = uncompiled_data_with_preparse_data();

View File

@ -549,13 +549,25 @@ void SharedFunctionInfo::InitFromFunctionLiteral(
if (scope_data != nullptr) {
Handle<PreparseData> preparse_data = scope_data->Serialize(isolate);
data = isolate->factory()->NewUncompiledDataWithPreparseData(
lit->GetInferredName(isolate), lit->start_position(),
lit->end_position(), preparse_data);
if (lit->should_parallel_compile()) {
data = isolate->factory()->NewUncompiledDataWithPreparseDataAndJob(
lit->GetInferredName(isolate), lit->start_position(),
lit->end_position(), preparse_data);
} else {
data = isolate->factory()->NewUncompiledDataWithPreparseData(
lit->GetInferredName(isolate), lit->start_position(),
lit->end_position(), preparse_data);
}
} else {
data = isolate->factory()->NewUncompiledDataWithoutPreparseData(
lit->GetInferredName(isolate), lit->start_position(),
lit->end_position());
if (lit->should_parallel_compile()) {
data = isolate->factory()->NewUncompiledDataWithoutPreparseDataWithJob(
lit->GetInferredName(isolate), lit->start_position(),
lit->end_position());
} else {
data = isolate->factory()->NewUncompiledDataWithoutPreparseData(
lit->GetInferredName(isolate), lit->start_position(),
lit->end_position());
}
}
shared_info->set_uncompiled_data(*data);

View File

@ -145,6 +145,31 @@ class UncompiledDataWithPreparseData
TQ_OBJECT_CONSTRUCTORS(UncompiledDataWithPreparseData)
};
// Class representing data for an uncompiled function that does not have any
// data from the pre-parser, either because it's a leaf function or because the
// pre-parser bailed out, but has a job pointer.
class UncompiledDataWithoutPreparseDataWithJob
: public TorqueGeneratedUncompiledDataWithoutPreparseDataWithJob<
UncompiledDataWithoutPreparseDataWithJob,
UncompiledDataWithoutPreparseData> {
public:
class BodyDescriptor;
TQ_OBJECT_CONSTRUCTORS(UncompiledDataWithoutPreparseDataWithJob)
};
// Class representing data for an uncompiled function that has pre-parsed scope
// data and a job pointer.
class UncompiledDataWithPreparseDataAndJob
: public TorqueGeneratedUncompiledDataWithPreparseDataAndJob<
UncompiledDataWithPreparseDataAndJob,
UncompiledDataWithPreparseData> {
public:
class BodyDescriptor;
TQ_OBJECT_CONSTRUCTORS(UncompiledDataWithPreparseDataAndJob)
};
class InterpreterData
: public TorqueGeneratedInterpreterData<InterpreterData, Struct> {
public:
@ -351,6 +376,7 @@ class SharedFunctionInfo
inline void set_uncompiled_data_with_preparse_data(
UncompiledDataWithPreparseData data);
inline bool HasUncompiledDataWithoutPreparseData() const;
inline void ClearUncompiledDataJobPointer();
// Clear out pre-parsed scope data from UncompiledDataWithPreparseData,
// turning it into UncompiledDataWithoutPreparseData.

View File

@ -135,6 +135,24 @@ extern class UncompiledDataWithPreparseData extends UncompiledData {
preparse_data: PreparseData;
}
@generateBodyDescriptor
@generateUniqueMap
@generateFactoryFunction
extern class UncompiledDataWithoutPreparseDataWithJob extends
UncompiledDataWithoutPreparseData {
// TODO(v8:10391): Define the field as ExternalPointer or move jobs into cage.
job: RawPtr;
}
@generateBodyDescriptor
@generateUniqueMap
@generateFactoryFunction
extern class UncompiledDataWithPreparseDataAndJob extends
UncompiledDataWithPreparseData {
// TODO(v8:10391): Define the field as ExternalPointer or move jobs into cage.
job: RawPtr;
}
@export
class OnHeapBasicBlockProfilerData extends HeapObject {
block_ids: ByteArray; // Stored as 4-byte ints

View File

@ -201,6 +201,25 @@ void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
return;
}
if (obj->IsUncompiledDataWithoutPreparseDataWithJob()) {
Handle<UncompiledDataWithoutPreparseDataWithJob> data =
Handle<UncompiledDataWithoutPreparseDataWithJob>::cast(obj);
Address job = data->job();
data->set_job(kNullAddress);
SerializeGeneric(data);
data->set_job(job);
return;
}
if (obj->IsUncompiledDataWithPreparseDataAndJob()) {
Handle<UncompiledDataWithPreparseDataAndJob> data =
Handle<UncompiledDataWithPreparseDataAndJob>::cast(obj);
Address job = data->job();
data->set_job(kNullAddress);
SerializeGeneric(data);
data->set_job(job);
return;
}
// NOTE(mmarchini): If we try to serialize an InterpreterData our process
// will crash since it stores a code object. Instead, we serialize the
// bytecode array stored within the InterpreterData, which is the important

View File

@ -25,6 +25,12 @@
#include "test/unittests/test-utils.h"
#include "testing/gtest/include/gtest/gtest.h"
#ifdef DEBUG
#define DEBUG_ASSERT_EQ ASSERT_EQ
#else
#define DEBUG_ASSERT_EQ(...)
#endif
namespace v8 {
namespace internal {
@ -397,11 +403,17 @@ TEST_F(LazyCompileDispatcherTest, IdleTaskNoIdleTime) {
EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 0u);
// Run compile steps.
platform.RunJobTasksAndBlock(V8::GetCurrentPlatform());
// Job should be ready to finalize.
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 1);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 0u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 1u);
ASSERT_EQ(
dispatcher.GetJobFor(shared, base::MutexGuard(&dispatcher.mutex_))->state,
LazyCompileDispatcher::Job::State::kReadyToFinalize);
@ -415,7 +427,8 @@ TEST_F(LazyCompileDispatcherTest, IdleTaskNoIdleTime) {
ASSERT_TRUE(platform.IdleTaskPending());
// Job should be ready to finalize.
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 1);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 0u);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 1u);
ASSERT_EQ(
dispatcher.GetJobFor(shared, base::MutexGuard(&dispatcher.mutex_))->state,
LazyCompileDispatcher::Job::State::kReadyToFinalize);
@ -444,11 +457,17 @@ TEST_F(LazyCompileDispatcherTest, IdleTaskSmallIdleTime) {
EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_1);
EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_2);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 2u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 2u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 0u);
// Run compile steps.
platform.RunJobTasksAndBlock(V8::GetCurrentPlatform());
// Both jobs should be ready to finalize.
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 2);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 2u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 0u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 2u);
ASSERT_EQ(
dispatcher.GetJobFor(shared_1, base::MutexGuard(&dispatcher.mutex_))
->state,
@ -464,7 +483,9 @@ TEST_F(LazyCompileDispatcherTest, IdleTaskSmallIdleTime) {
platform.RunIdleTask(2.0, 1.0);
// Only one of the jobs should be finalized.
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 1);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 0u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 1u);
if (dispatcher.IsEnqueued(shared_1)) {
ASSERT_EQ(
dispatcher.GetJobFor(shared_1, base::MutexGuard(&dispatcher.mutex_))
@ -532,7 +553,9 @@ TEST_F(LazyCompileDispatcherTest, FinishNowWithWorkerTask) {
ASSERT_TRUE(dispatcher.IsEnqueued(shared));
ASSERT_FALSE(shared->is_compiled());
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 1);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 0u);
ASSERT_NE(
dispatcher.GetJobFor(shared, base::MutexGuard(&dispatcher.mutex_))->state,
LazyCompileDispatcher::Job::State::kReadyToFinalize);
@ -544,6 +567,7 @@ TEST_F(LazyCompileDispatcherTest, FinishNowWithWorkerTask) {
ASSERT_TRUE(dispatcher.FinishNow(shared));
// Finishing removes the SFI from the queue.
ASSERT_FALSE(dispatcher.IsEnqueued(shared));
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 0u);
ASSERT_TRUE(shared->is_compiled());
if (platform.IdleTaskPending()) platform.ClearIdleTask();
ASSERT_FALSE(platform.JobTaskPending());
@ -620,7 +644,9 @@ TEST_F(LazyCompileDispatcherTest, AbortJobNotStarted) {
EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared);
ASSERT_FALSE(shared->is_compiled());
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 1);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 0u);
ASSERT_NE(
dispatcher.GetJobFor(shared, base::MutexGuard(&dispatcher.mutex_))->state,
LazyCompileDispatcher::Job::State::kReadyToFinalize);
@ -645,7 +671,9 @@ TEST_F(LazyCompileDispatcherTest, AbortJobAlreadyStarted) {
EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared);
ASSERT_FALSE(shared->is_compiled());
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 1);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 0u);
ASSERT_NE(
dispatcher.GetJobFor(shared, base::MutexGuard(&dispatcher.mutex_))->state,
LazyCompileDispatcher::Job::State::kReadyToFinalize);
@ -674,7 +702,9 @@ TEST_F(LazyCompileDispatcherTest, AbortJobAlreadyStarted) {
// Job should have finished running and then been aborted.
ASSERT_FALSE(shared->is_compiled());
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 1);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 1u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 0u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 1u);
ASSERT_EQ(
dispatcher.GetJobFor(shared, base::MutexGuard(&dispatcher.mutex_))->state,
LazyCompileDispatcher::Job::State::kAborted);
@ -760,7 +790,9 @@ TEST_F(LazyCompileDispatcherTest, CompileMultipleOnBackgroundThread) {
EnqueueUnoptimizedCompileJob(&dispatcher, i_isolate(), shared_2);
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 2);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 2u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 2u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 0u);
ASSERT_NE(
dispatcher.GetJobFor(shared_1, base::MutexGuard(&dispatcher.mutex_))
->state,
@ -781,7 +813,9 @@ TEST_F(LazyCompileDispatcherTest, CompileMultipleOnBackgroundThread) {
ASSERT_TRUE(platform.IdleTaskPending());
ASSERT_FALSE(platform.JobTaskPending());
ASSERT_EQ(dispatcher.shared_to_unoptimized_job_.size(), 2);
DEBUG_ASSERT_EQ(dispatcher.all_jobs_.size(), 2u);
ASSERT_EQ(dispatcher.pending_background_jobs_.size(), 0u);
ASSERT_EQ(dispatcher.finalizable_jobs_.size(), 2u);
ASSERT_EQ(
dispatcher.GetJobFor(shared_1, base::MutexGuard(&dispatcher.mutex_))
->state,

View File

@ -43,7 +43,7 @@ Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
shared->set_function_literal_id(function_literal_id);
// Ensure that the function can be compiled lazily.
shared->set_uncompiled_data(
*isolate->factory()->NewUncompiledDataWithoutPreparseData(
*isolate->factory()->NewUncompiledDataWithoutPreparseDataWithJob(
ReadOnlyRoots(isolate).empty_string_handle(), 0, source->length()));
// Make sure we have an outer scope info, even though it's empty
shared->set_raw_outer_scope_info_or_feedback_metadata(

View File

@ -113,59 +113,61 @@ INSTANCE_TYPES = {
209: "TURBOFAN_OTHER_NUMBER_CONSTANT_TYPE_TYPE",
210: "TURBOFAN_RANGE_TYPE_TYPE",
211: "TURBOFAN_UNION_TYPE_TYPE",
212: "WASM_FUNCTION_DATA_TYPE",
213: "WASM_CAPI_FUNCTION_DATA_TYPE",
214: "WASM_EXPORTED_FUNCTION_DATA_TYPE",
215: "WASM_JS_FUNCTION_DATA_TYPE",
216: "EXPORTED_SUB_CLASS_BASE_TYPE",
217: "EXPORTED_SUB_CLASS_TYPE",
218: "EXPORTED_SUB_CLASS2_TYPE",
219: "SMALL_ORDERED_HASH_MAP_TYPE",
220: "SMALL_ORDERED_HASH_SET_TYPE",
221: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
222: "ABSTRACT_INTERNAL_CLASS_SUBCLASS1_TYPE",
223: "ABSTRACT_INTERNAL_CLASS_SUBCLASS2_TYPE",
224: "DESCRIPTOR_ARRAY_TYPE",
225: "STRONG_DESCRIPTOR_ARRAY_TYPE",
226: "SOURCE_TEXT_MODULE_TYPE",
227: "SYNTHETIC_MODULE_TYPE",
228: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE",
229: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE",
230: "WEAK_FIXED_ARRAY_TYPE",
231: "TRANSITION_ARRAY_TYPE",
232: "CELL_TYPE",
233: "CODE_TYPE",
234: "CODE_DATA_CONTAINER_TYPE",
235: "COVERAGE_INFO_TYPE",
236: "EMBEDDER_DATA_ARRAY_TYPE",
237: "FEEDBACK_METADATA_TYPE",
238: "FEEDBACK_VECTOR_TYPE",
239: "FILLER_TYPE",
240: "FREE_SPACE_TYPE",
241: "INTERNAL_CLASS_TYPE",
242: "INTERNAL_CLASS_WITH_STRUCT_ELEMENTS_TYPE",
243: "MAP_TYPE",
244: "MEGA_DOM_HANDLER_TYPE",
245: "ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE",
246: "PREPARSE_DATA_TYPE",
247: "PROPERTY_ARRAY_TYPE",
248: "PROPERTY_CELL_TYPE",
249: "SCOPE_INFO_TYPE",
250: "SHARED_FUNCTION_INFO_TYPE",
251: "SMI_BOX_TYPE",
252: "SMI_PAIR_TYPE",
253: "SORT_STATE_TYPE",
254: "SWISS_NAME_DICTIONARY_TYPE",
255: "WASM_API_FUNCTION_REF_TYPE",
256: "WEAK_ARRAY_LIST_TYPE",
257: "WEAK_CELL_TYPE",
258: "WASM_ARRAY_TYPE",
259: "WASM_STRUCT_TYPE",
260: "JS_PROXY_TYPE",
212: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE",
213: "UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE",
214: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE",
215: "UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE",
216: "WASM_FUNCTION_DATA_TYPE",
217: "WASM_CAPI_FUNCTION_DATA_TYPE",
218: "WASM_EXPORTED_FUNCTION_DATA_TYPE",
219: "WASM_JS_FUNCTION_DATA_TYPE",
220: "EXPORTED_SUB_CLASS_BASE_TYPE",
221: "EXPORTED_SUB_CLASS_TYPE",
222: "EXPORTED_SUB_CLASS2_TYPE",
223: "SMALL_ORDERED_HASH_MAP_TYPE",
224: "SMALL_ORDERED_HASH_SET_TYPE",
225: "SMALL_ORDERED_NAME_DICTIONARY_TYPE",
226: "ABSTRACT_INTERNAL_CLASS_SUBCLASS1_TYPE",
227: "ABSTRACT_INTERNAL_CLASS_SUBCLASS2_TYPE",
228: "DESCRIPTOR_ARRAY_TYPE",
229: "STRONG_DESCRIPTOR_ARRAY_TYPE",
230: "SOURCE_TEXT_MODULE_TYPE",
231: "SYNTHETIC_MODULE_TYPE",
232: "WEAK_FIXED_ARRAY_TYPE",
233: "TRANSITION_ARRAY_TYPE",
234: "CELL_TYPE",
235: "CODE_TYPE",
236: "CODE_DATA_CONTAINER_TYPE",
237: "COVERAGE_INFO_TYPE",
238: "EMBEDDER_DATA_ARRAY_TYPE",
239: "FEEDBACK_METADATA_TYPE",
240: "FEEDBACK_VECTOR_TYPE",
241: "FILLER_TYPE",
242: "FREE_SPACE_TYPE",
243: "INTERNAL_CLASS_TYPE",
244: "INTERNAL_CLASS_WITH_STRUCT_ELEMENTS_TYPE",
245: "MAP_TYPE",
246: "MEGA_DOM_HANDLER_TYPE",
247: "ON_HEAP_BASIC_BLOCK_PROFILER_DATA_TYPE",
248: "PREPARSE_DATA_TYPE",
249: "PROPERTY_ARRAY_TYPE",
250: "PROPERTY_CELL_TYPE",
251: "SCOPE_INFO_TYPE",
252: "SHARED_FUNCTION_INFO_TYPE",
253: "SMI_BOX_TYPE",
254: "SMI_PAIR_TYPE",
255: "SORT_STATE_TYPE",
256: "SWISS_NAME_DICTIONARY_TYPE",
257: "WASM_API_FUNCTION_REF_TYPE",
258: "WEAK_ARRAY_LIST_TYPE",
259: "WEAK_CELL_TYPE",
260: "WASM_ARRAY_TYPE",
261: "WASM_STRUCT_TYPE",
262: "JS_PROXY_TYPE",
1057: "JS_OBJECT_TYPE",
261: "JS_GLOBAL_OBJECT_TYPE",
262: "JS_GLOBAL_PROXY_TYPE",
263: "JS_MODULE_NAMESPACE_TYPE",
263: "JS_GLOBAL_OBJECT_TYPE",
264: "JS_GLOBAL_PROXY_TYPE",
265: "JS_MODULE_NAMESPACE_TYPE",
1040: "JS_SPECIAL_API_OBJECT_TYPE",
1041: "JS_PRIMITIVE_WRAPPER_TYPE",
1058: "JS_API_OBJECT_TYPE",
@ -260,16 +262,16 @@ INSTANCE_TYPES = {
# List of known V8 maps.
KNOWN_MAPS = {
("read_only_space", 0x02119): (243, "MetaMap"),
("read_only_space", 0x02119): (245, "MetaMap"),
("read_only_space", 0x02141): (131, "NullMap"),
("read_only_space", 0x02169): (225, "StrongDescriptorArrayMap"),
("read_only_space", 0x02191): (256, "WeakArrayListMap"),
("read_only_space", 0x02169): (229, "StrongDescriptorArrayMap"),
("read_only_space", 0x02191): (258, "WeakArrayListMap"),
("read_only_space", 0x021d5): (156, "EnumCacheMap"),
("read_only_space", 0x02209): (176, "FixedArrayMap"),
("read_only_space", 0x02255): (8, "OneByteInternalizedStringMap"),
("read_only_space", 0x022a1): (240, "FreeSpaceMap"),
("read_only_space", 0x022c9): (239, "OnePointerFillerMap"),
("read_only_space", 0x022f1): (239, "TwoPointerFillerMap"),
("read_only_space", 0x022a1): (242, "FreeSpaceMap"),
("read_only_space", 0x022c9): (241, "OnePointerFillerMap"),
("read_only_space", 0x022f1): (241, "TwoPointerFillerMap"),
("read_only_space", 0x02319): (131, "UninitializedMap"),
("read_only_space", 0x02391): (131, "UndefinedMap"),
("read_only_space", 0x023d5): (130, "HeapNumberMap"),
@ -280,15 +282,15 @@ KNOWN_MAPS = {
("read_only_space", 0x0255d): (177, "HashTableMap"),
("read_only_space", 0x02585): (128, "SymbolMap"),
("read_only_space", 0x025ad): (40, "OneByteStringMap"),
("read_only_space", 0x025d5): (249, "ScopeInfoMap"),
("read_only_space", 0x025fd): (250, "SharedFunctionInfoMap"),
("read_only_space", 0x02625): (233, "CodeMap"),
("read_only_space", 0x0264d): (232, "CellMap"),
("read_only_space", 0x02675): (248, "GlobalPropertyCellMap"),
("read_only_space", 0x025d5): (251, "ScopeInfoMap"),
("read_only_space", 0x025fd): (252, "SharedFunctionInfoMap"),
("read_only_space", 0x02625): (235, "CodeMap"),
("read_only_space", 0x0264d): (234, "CellMap"),
("read_only_space", 0x02675): (250, "GlobalPropertyCellMap"),
("read_only_space", 0x0269d): (204, "ForeignMap"),
("read_only_space", 0x026c5): (231, "TransitionArrayMap"),
("read_only_space", 0x026c5): (233, "TransitionArrayMap"),
("read_only_space", 0x026ed): (45, "ThinOneByteStringMap"),
("read_only_space", 0x02715): (238, "FeedbackVectorMap"),
("read_only_space", 0x02715): (240, "FeedbackVectorMap"),
("read_only_space", 0x0274d): (131, "ArgumentsMarkerMap"),
("read_only_space", 0x027ad): (131, "ExceptionMap"),
("read_only_space", 0x02809): (131, "TerminationExceptionMap"),
@ -296,17 +298,17 @@ KNOWN_MAPS = {
("read_only_space", 0x028d1): (131, "StaleRegisterMap"),
("read_only_space", 0x02931): (188, "ScriptContextTableMap"),
("read_only_space", 0x02959): (186, "ClosureFeedbackCellArrayMap"),
("read_only_space", 0x02981): (237, "FeedbackMetadataArrayMap"),
("read_only_space", 0x02981): (239, "FeedbackMetadataArrayMap"),
("read_only_space", 0x029a9): (176, "ArrayListMap"),
("read_only_space", 0x029d1): (129, "BigIntMap"),
("read_only_space", 0x029f9): (187, "ObjectBoilerplateDescriptionMap"),
("read_only_space", 0x02a21): (190, "BytecodeArrayMap"),
("read_only_space", 0x02a49): (234, "CodeDataContainerMap"),
("read_only_space", 0x02a71): (235, "CoverageInfoMap"),
("read_only_space", 0x02a49): (236, "CodeDataContainerMap"),
("read_only_space", 0x02a71): (237, "CoverageInfoMap"),
("read_only_space", 0x02a99): (191, "FixedDoubleArrayMap"),
("read_only_space", 0x02ac1): (179, "GlobalDictionaryMap"),
("read_only_space", 0x02ae9): (157, "ManyClosuresCellMap"),
("read_only_space", 0x02b11): (244, "MegaDomHandlerMap"),
("read_only_space", 0x02b11): (246, "MegaDomHandlerMap"),
("read_only_space", 0x02b39): (176, "ModuleInfoMap"),
("read_only_space", 0x02b61): (180, "NameDictionaryMap"),
("read_only_space", 0x02b89): (157, "NoClosuresCellMap"),
@ -315,28 +317,28 @@ KNOWN_MAPS = {
("read_only_space", 0x02c01): (182, "OrderedHashMapMap"),
("read_only_space", 0x02c29): (183, "OrderedHashSetMap"),
("read_only_space", 0x02c51): (184, "OrderedNameDictionaryMap"),
("read_only_space", 0x02c79): (246, "PreparseDataMap"),
("read_only_space", 0x02ca1): (247, "PropertyArrayMap"),
("read_only_space", 0x02c79): (248, "PreparseDataMap"),
("read_only_space", 0x02ca1): (249, "PropertyArrayMap"),
("read_only_space", 0x02cc9): (153, "SideEffectCallHandlerInfoMap"),
("read_only_space", 0x02cf1): (153, "SideEffectFreeCallHandlerInfoMap"),
("read_only_space", 0x02d19): (153, "NextCallSideEffectFreeCallHandlerInfoMap"),
("read_only_space", 0x02d41): (185, "SimpleNumberDictionaryMap"),
("read_only_space", 0x02d69): (219, "SmallOrderedHashMapMap"),
("read_only_space", 0x02d91): (220, "SmallOrderedHashSetMap"),
("read_only_space", 0x02db9): (221, "SmallOrderedNameDictionaryMap"),
("read_only_space", 0x02de1): (226, "SourceTextModuleMap"),
("read_only_space", 0x02e09): (254, "SwissNameDictionaryMap"),
("read_only_space", 0x02e31): (227, "SyntheticModuleMap"),
("read_only_space", 0x02e59): (255, "WasmApiFunctionRefMap"),
("read_only_space", 0x02e81): (213, "WasmCapiFunctionDataMap"),
("read_only_space", 0x02ea9): (214, "WasmExportedFunctionDataMap"),
("read_only_space", 0x02d69): (223, "SmallOrderedHashMapMap"),
("read_only_space", 0x02d91): (224, "SmallOrderedHashSetMap"),
("read_only_space", 0x02db9): (225, "SmallOrderedNameDictionaryMap"),
("read_only_space", 0x02de1): (230, "SourceTextModuleMap"),
("read_only_space", 0x02e09): (256, "SwissNameDictionaryMap"),
("read_only_space", 0x02e31): (231, "SyntheticModuleMap"),
("read_only_space", 0x02e59): (257, "WasmApiFunctionRefMap"),
("read_only_space", 0x02e81): (217, "WasmCapiFunctionDataMap"),
("read_only_space", 0x02ea9): (218, "WasmExportedFunctionDataMap"),
("read_only_space", 0x02ed1): (205, "WasmInternalFunctionMap"),
("read_only_space", 0x02ef9): (215, "WasmJSFunctionDataMap"),
("read_only_space", 0x02ef9): (219, "WasmJSFunctionDataMap"),
("read_only_space", 0x02f21): (206, "WasmTypeInfoMap"),
("read_only_space", 0x02f49): (230, "WeakFixedArrayMap"),
("read_only_space", 0x02f49): (232, "WeakFixedArrayMap"),
("read_only_space", 0x02f71): (178, "EphemeronHashTableMap"),
("read_only_space", 0x02f99): (236, "EmbedderDataArrayMap"),
("read_only_space", 0x02fc1): (257, "WeakCellMap"),
("read_only_space", 0x02f99): (238, "EmbedderDataArrayMap"),
("read_only_space", 0x02fc1): (259, "WeakCellMap"),
("read_only_space", 0x02fe9): (32, "StringMap"),
("read_only_space", 0x03011): (41, "ConsOneByteStringMap"),
("read_only_space", 0x03039): (33, "ConsStringMap"),
@ -399,35 +401,37 @@ KNOWN_MAPS = {
("read_only_space", 0x06261): (174, "WasmExceptionTagMap"),
("read_only_space", 0x06289): (175, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x062b1): (193, "SloppyArgumentsElementsMap"),
("read_only_space", 0x062d9): (224, "DescriptorArrayMap"),
("read_only_space", 0x06301): (229, "UncompiledDataWithoutPreparseDataMap"),
("read_only_space", 0x06329): (228, "UncompiledDataWithPreparseDataMap"),
("read_only_space", 0x06351): (245, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x06379): (207, "TurbofanBitsetTypeMap"),
("read_only_space", 0x063a1): (211, "TurbofanUnionTypeMap"),
("read_only_space", 0x063c9): (210, "TurbofanRangeTypeMap"),
("read_only_space", 0x063f1): (208, "TurbofanHeapConstantTypeMap"),
("read_only_space", 0x06419): (209, "TurbofanOtherNumberConstantTypeMap"),
("read_only_space", 0x06441): (241, "InternalClassMap"),
("read_only_space", 0x06469): (252, "SmiPairMap"),
("read_only_space", 0x06491): (251, "SmiBoxMap"),
("read_only_space", 0x064b9): (216, "ExportedSubClassBaseMap"),
("read_only_space", 0x064e1): (217, "ExportedSubClassMap"),
("read_only_space", 0x06509): (222, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x06531): (223, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x06559): (192, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x06581): (242, "InternalClassWithStructElementsMap"),
("read_only_space", 0x065a9): (218, "ExportedSubClass2Map"),
("read_only_space", 0x065d1): (253, "SortStateMap"),
("read_only_space", 0x065f9): (146, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x06621): (146, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x06649): (137, "LoadHandler1Map"),
("read_only_space", 0x06671): (137, "LoadHandler2Map"),
("read_only_space", 0x06699): (137, "LoadHandler3Map"),
("read_only_space", 0x066c1): (138, "StoreHandler0Map"),
("read_only_space", 0x066e9): (138, "StoreHandler1Map"),
("read_only_space", 0x06711): (138, "StoreHandler2Map"),
("read_only_space", 0x06739): (138, "StoreHandler3Map"),
("read_only_space", 0x062d9): (228, "DescriptorArrayMap"),
("read_only_space", 0x06301): (214, "UncompiledDataWithoutPreparseDataMap"),
("read_only_space", 0x06329): (212, "UncompiledDataWithPreparseDataMap"),
("read_only_space", 0x06351): (215, "UncompiledDataWithoutPreparseDataWithJobMap"),
("read_only_space", 0x06379): (213, "UncompiledDataWithPreparseDataAndJobMap"),
("read_only_space", 0x063a1): (247, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x063c9): (207, "TurbofanBitsetTypeMap"),
("read_only_space", 0x063f1): (211, "TurbofanUnionTypeMap"),
("read_only_space", 0x06419): (210, "TurbofanRangeTypeMap"),
("read_only_space", 0x06441): (208, "TurbofanHeapConstantTypeMap"),
("read_only_space", 0x06469): (209, "TurbofanOtherNumberConstantTypeMap"),
("read_only_space", 0x06491): (243, "InternalClassMap"),
("read_only_space", 0x064b9): (254, "SmiPairMap"),
("read_only_space", 0x064e1): (253, "SmiBoxMap"),
("read_only_space", 0x06509): (220, "ExportedSubClassBaseMap"),
("read_only_space", 0x06531): (221, "ExportedSubClassMap"),
("read_only_space", 0x06559): (226, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x06581): (227, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x065a9): (192, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x065d1): (244, "InternalClassWithStructElementsMap"),
("read_only_space", 0x065f9): (222, "ExportedSubClass2Map"),
("read_only_space", 0x06621): (255, "SortStateMap"),
("read_only_space", 0x06649): (146, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x06671): (146, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x06699): (137, "LoadHandler1Map"),
("read_only_space", 0x066c1): (137, "LoadHandler2Map"),
("read_only_space", 0x066e9): (137, "LoadHandler3Map"),
("read_only_space", 0x06711): (138, "StoreHandler0Map"),
("read_only_space", 0x06739): (138, "StoreHandler1Map"),
("read_only_space", 0x06761): (138, "StoreHandler2Map"),
("read_only_space", 0x06789): (138, "StoreHandler3Map"),
("map_space", 0x02119): (1057, "ExternalMap"),
("map_space", 0x02141): (2114, "JSMessageObjectMap"),
}