11cb0ef41Sopenharmony_ci// Copyright 2016 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/compiler-dispatcher/lazy-compile-dispatcher.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <atomic>
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#include "include/v8-platform.h"
101cb0ef41Sopenharmony_ci#include "src/ast/ast.h"
111cb0ef41Sopenharmony_ci#include "src/base/platform/mutex.h"
121cb0ef41Sopenharmony_ci#include "src/base/platform/time.h"
131cb0ef41Sopenharmony_ci#include "src/codegen/compiler.h"
141cb0ef41Sopenharmony_ci#include "src/common/globals.h"
151cb0ef41Sopenharmony_ci#include "src/execution/isolate.h"
161cb0ef41Sopenharmony_ci#include "src/flags/flags.h"
171cb0ef41Sopenharmony_ci#include "src/handles/global-handles-inl.h"
181cb0ef41Sopenharmony_ci#include "src/heap/parked-scope.h"
191cb0ef41Sopenharmony_ci#include "src/logging/counters.h"
201cb0ef41Sopenharmony_ci#include "src/logging/runtime-call-stats-scope.h"
211cb0ef41Sopenharmony_ci#include "src/numbers/hash-seed-inl.h"
221cb0ef41Sopenharmony_ci#include "src/objects/instance-type.h"
231cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h"
241cb0ef41Sopenharmony_ci#include "src/parsing/parse-info.h"
251cb0ef41Sopenharmony_ci#include "src/parsing/parser.h"
261cb0ef41Sopenharmony_ci#include "src/roots/roots.h"
271cb0ef41Sopenharmony_ci#include "src/sandbox/external-pointer.h"
281cb0ef41Sopenharmony_ci#include "src/tasks/cancelable-task.h"
291cb0ef41Sopenharmony_ci#include "src/tasks/task-utils.h"
301cb0ef41Sopenharmony_ci#include "src/zone/zone-list-inl.h"  // crbug.com/v8/8816
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cinamespace v8 {
331cb0ef41Sopenharmony_cinamespace internal {
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci// The maximum amount of time we should allow a single function's FinishNow to
361cb0ef41Sopenharmony_ci// spend opportunistically finalizing other finalizable jobs.
371cb0ef41Sopenharmony_cistatic constexpr int kMaxOpportunisticFinalizeTimeMs = 1;
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ciclass LazyCompileDispatcher::JobTask : public v8::JobTask {
401cb0ef41Sopenharmony_ci public:
411cb0ef41Sopenharmony_ci  explicit JobTask(LazyCompileDispatcher* lazy_compile_dispatcher)
421cb0ef41Sopenharmony_ci      : lazy_compile_dispatcher_(lazy_compile_dispatcher) {}
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  void Run(JobDelegate* delegate) final {
451cb0ef41Sopenharmony_ci    lazy_compile_dispatcher_->DoBackgroundWork(delegate);
461cb0ef41Sopenharmony_ci  }
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  size_t GetMaxConcurrency(size_t worker_count) const final {
491cb0ef41Sopenharmony_ci    size_t n = lazy_compile_dispatcher_->num_jobs_for_background_.load(
501cb0ef41Sopenharmony_ci        std::memory_order_relaxed);
511cb0ef41Sopenharmony_ci    if (FLAG_lazy_compile_dispatcher_max_threads == 0) return n;
521cb0ef41Sopenharmony_ci    return std::min(
531cb0ef41Sopenharmony_ci        n, static_cast<size_t>(FLAG_lazy_compile_dispatcher_max_threads));
541cb0ef41Sopenharmony_ci  }
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_ci private:
571cb0ef41Sopenharmony_ci  LazyCompileDispatcher* lazy_compile_dispatcher_;
581cb0ef41Sopenharmony_ci};
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ciLazyCompileDispatcher::Job::Job(std::unique_ptr<BackgroundCompileTask> task)
611cb0ef41Sopenharmony_ci    : task(std::move(task)), state(Job::State::kPending) {}
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ciLazyCompileDispatcher::Job::~Job() = default;
641cb0ef41Sopenharmony_ci
651cb0ef41Sopenharmony_ciLazyCompileDispatcher::LazyCompileDispatcher(Isolate* isolate,
661cb0ef41Sopenharmony_ci                                             Platform* platform,
671cb0ef41Sopenharmony_ci                                             size_t max_stack_size)
681cb0ef41Sopenharmony_ci    : isolate_(isolate),
691cb0ef41Sopenharmony_ci      worker_thread_runtime_call_stats_(
701cb0ef41Sopenharmony_ci          isolate->counters()->worker_thread_runtime_call_stats()),
711cb0ef41Sopenharmony_ci      background_compile_timer_(
721cb0ef41Sopenharmony_ci          isolate->counters()->compile_function_on_background()),
731cb0ef41Sopenharmony_ci      taskrunner_(platform->GetForegroundTaskRunner(
741cb0ef41Sopenharmony_ci          reinterpret_cast<v8::Isolate*>(isolate))),
751cb0ef41Sopenharmony_ci      platform_(platform),
761cb0ef41Sopenharmony_ci      max_stack_size_(max_stack_size),
771cb0ef41Sopenharmony_ci      trace_compiler_dispatcher_(FLAG_trace_compiler_dispatcher),
781cb0ef41Sopenharmony_ci      idle_task_manager_(new CancelableTaskManager()),
791cb0ef41Sopenharmony_ci      idle_task_scheduled_(false),
801cb0ef41Sopenharmony_ci      num_jobs_for_background_(0),
811cb0ef41Sopenharmony_ci      main_thread_blocking_on_job_(nullptr),
821cb0ef41Sopenharmony_ci      block_for_testing_(false),
831cb0ef41Sopenharmony_ci      semaphore_for_testing_(0) {
841cb0ef41Sopenharmony_ci  job_handle_ = platform_->PostJob(TaskPriority::kUserVisible,
851cb0ef41Sopenharmony_ci                                   std::make_unique<JobTask>(this));
861cb0ef41Sopenharmony_ci}
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ciLazyCompileDispatcher::~LazyCompileDispatcher() {
891cb0ef41Sopenharmony_ci  // AbortAll must be called before LazyCompileDispatcher is destroyed.
901cb0ef41Sopenharmony_ci  CHECK(!job_handle_->IsValid());
911cb0ef41Sopenharmony_ci}
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_cinamespace {
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_ci// If the SharedFunctionInfo's UncompiledData has a job slot, then write into
961cb0ef41Sopenharmony_ci// it. Otherwise, allocate a new UncompiledData with a job slot, and then write
971cb0ef41Sopenharmony_ci// into that. Since we have two optional slots (preparse data and job), this
981cb0ef41Sopenharmony_ci// gets a little messy.
991cb0ef41Sopenharmony_civoid SetUncompiledDataJobPointer(LocalIsolate* isolate,
1001cb0ef41Sopenharmony_ci                                 Handle<SharedFunctionInfo> shared_info,
1011cb0ef41Sopenharmony_ci                                 Address job_address) {
1021cb0ef41Sopenharmony_ci  UncompiledData uncompiled_data = shared_info->uncompiled_data();
1031cb0ef41Sopenharmony_ci  switch (uncompiled_data.map(isolate).instance_type()) {
1041cb0ef41Sopenharmony_ci    // The easy cases -- we already have a job slot, so can write into it and
1051cb0ef41Sopenharmony_ci    // return.
1061cb0ef41Sopenharmony_ci    case UNCOMPILED_DATA_WITH_PREPARSE_DATA_AND_JOB_TYPE:
1071cb0ef41Sopenharmony_ci      UncompiledDataWithPreparseDataAndJob::cast(uncompiled_data)
1081cb0ef41Sopenharmony_ci          .set_job(job_address);
1091cb0ef41Sopenharmony_ci      break;
1101cb0ef41Sopenharmony_ci    case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_WITH_JOB_TYPE:
1111cb0ef41Sopenharmony_ci      UncompiledDataWithoutPreparseDataWithJob::cast(uncompiled_data)
1121cb0ef41Sopenharmony_ci          .set_job(job_address);
1131cb0ef41Sopenharmony_ci      break;
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci    // Otherwise, we'll have to allocate a new UncompiledData (with or without
1161cb0ef41Sopenharmony_ci    // preparse data as appropriate), set the job pointer on that, and update
1171cb0ef41Sopenharmony_ci    // the SharedFunctionInfo to use the new UncompiledData
1181cb0ef41Sopenharmony_ci    case UNCOMPILED_DATA_WITH_PREPARSE_DATA_TYPE: {
1191cb0ef41Sopenharmony_ci      Handle<String> inferred_name(uncompiled_data.inferred_name(), isolate);
1201cb0ef41Sopenharmony_ci      Handle<PreparseData> preparse_data(
1211cb0ef41Sopenharmony_ci          UncompiledDataWithPreparseData::cast(uncompiled_data).preparse_data(),
1221cb0ef41Sopenharmony_ci          isolate);
1231cb0ef41Sopenharmony_ci      Handle<UncompiledDataWithPreparseDataAndJob> new_uncompiled_data =
1241cb0ef41Sopenharmony_ci          isolate->factory()->NewUncompiledDataWithPreparseDataAndJob(
1251cb0ef41Sopenharmony_ci              inferred_name, uncompiled_data.start_position(),
1261cb0ef41Sopenharmony_ci              uncompiled_data.end_position(), preparse_data);
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci      new_uncompiled_data->set_job(job_address);
1291cb0ef41Sopenharmony_ci      shared_info->set_uncompiled_data(*new_uncompiled_data);
1301cb0ef41Sopenharmony_ci      break;
1311cb0ef41Sopenharmony_ci    }
1321cb0ef41Sopenharmony_ci    case UNCOMPILED_DATA_WITHOUT_PREPARSE_DATA_TYPE: {
1331cb0ef41Sopenharmony_ci      DCHECK(uncompiled_data.IsUncompiledDataWithoutPreparseData());
1341cb0ef41Sopenharmony_ci      Handle<String> inferred_name(uncompiled_data.inferred_name(), isolate);
1351cb0ef41Sopenharmony_ci      Handle<UncompiledDataWithoutPreparseDataWithJob> new_uncompiled_data =
1361cb0ef41Sopenharmony_ci          isolate->factory()->NewUncompiledDataWithoutPreparseDataWithJob(
1371cb0ef41Sopenharmony_ci              inferred_name, uncompiled_data.start_position(),
1381cb0ef41Sopenharmony_ci              uncompiled_data.end_position());
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci      new_uncompiled_data->set_job(job_address);
1411cb0ef41Sopenharmony_ci      shared_info->set_uncompiled_data(*new_uncompiled_data);
1421cb0ef41Sopenharmony_ci      break;
1431cb0ef41Sopenharmony_ci    }
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci    default:
1461cb0ef41Sopenharmony_ci      UNREACHABLE();
1471cb0ef41Sopenharmony_ci  }
1481cb0ef41Sopenharmony_ci}
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci}  // namespace
1511cb0ef41Sopenharmony_ci
1521cb0ef41Sopenharmony_civoid LazyCompileDispatcher::Enqueue(
1531cb0ef41Sopenharmony_ci    LocalIsolate* isolate, Handle<SharedFunctionInfo> shared_info,
1541cb0ef41Sopenharmony_ci    std::unique_ptr<Utf16CharacterStream> character_stream) {
1551cb0ef41Sopenharmony_ci  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
1561cb0ef41Sopenharmony_ci               "V8.LazyCompilerDispatcherEnqueue");
1571cb0ef41Sopenharmony_ci  RCS_SCOPE(isolate, RuntimeCallCounterId::kCompileEnqueueOnDispatcher);
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci  Job* job = new Job(std::make_unique<BackgroundCompileTask>(
1601cb0ef41Sopenharmony_ci      isolate_, shared_info, std::move(character_stream),
1611cb0ef41Sopenharmony_ci      worker_thread_runtime_call_stats_, background_compile_timer_,
1621cb0ef41Sopenharmony_ci      static_cast<int>(max_stack_size_)));
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  SetUncompiledDataJobPointer(isolate, shared_info,
1651cb0ef41Sopenharmony_ci                              reinterpret_cast<Address>(job));
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ci  // Post a a background worker task to perform the compilation on the worker
1681cb0ef41Sopenharmony_ci  // thread.
1691cb0ef41Sopenharmony_ci  {
1701cb0ef41Sopenharmony_ci    base::MutexGuard lock(&mutex_);
1711cb0ef41Sopenharmony_ci    if (trace_compiler_dispatcher_) {
1721cb0ef41Sopenharmony_ci      PrintF("LazyCompileDispatcher: enqueued job for ");
1731cb0ef41Sopenharmony_ci      shared_info->ShortPrint();
1741cb0ef41Sopenharmony_ci      PrintF("\n");
1751cb0ef41Sopenharmony_ci    }
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci#ifdef DEBUG
1781cb0ef41Sopenharmony_ci    all_jobs_.insert(job);
1791cb0ef41Sopenharmony_ci#endif
1801cb0ef41Sopenharmony_ci    pending_background_jobs_.push_back(job);
1811cb0ef41Sopenharmony_ci    NotifyAddedBackgroundJob(lock);
1821cb0ef41Sopenharmony_ci  }
1831cb0ef41Sopenharmony_ci  // This is not in NotifyAddedBackgroundJob to avoid being inside the mutex.
1841cb0ef41Sopenharmony_ci  job_handle_->NotifyConcurrencyIncrease();
1851cb0ef41Sopenharmony_ci}
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_cibool LazyCompileDispatcher::IsEnqueued(
1881cb0ef41Sopenharmony_ci    Handle<SharedFunctionInfo> function) const {
1891cb0ef41Sopenharmony_ci  Job* job = nullptr;
1901cb0ef41Sopenharmony_ci  Object function_data = function->function_data(kAcquireLoad);
1911cb0ef41Sopenharmony_ci  if (function_data.IsUncompiledDataWithPreparseDataAndJob()) {
1921cb0ef41Sopenharmony_ci    job = reinterpret_cast<Job*>(
1931cb0ef41Sopenharmony_ci        UncompiledDataWithPreparseDataAndJob::cast(function_data).job());
1941cb0ef41Sopenharmony_ci  } else if (function_data.IsUncompiledDataWithoutPreparseDataWithJob()) {
1951cb0ef41Sopenharmony_ci    job = reinterpret_cast<Job*>(
1961cb0ef41Sopenharmony_ci        UncompiledDataWithoutPreparseDataWithJob::cast(function_data).job());
1971cb0ef41Sopenharmony_ci  }
1981cb0ef41Sopenharmony_ci  return job != nullptr;
1991cb0ef41Sopenharmony_ci}
2001cb0ef41Sopenharmony_ci
2011cb0ef41Sopenharmony_civoid LazyCompileDispatcher::WaitForJobIfRunningOnBackground(
2021cb0ef41Sopenharmony_ci    Job* job, const base::MutexGuard& lock) {
2031cb0ef41Sopenharmony_ci  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
2041cb0ef41Sopenharmony_ci               "V8.LazyCompilerDispatcherWaitForBackgroundJob");
2051cb0ef41Sopenharmony_ci  RCS_SCOPE(isolate_, RuntimeCallCounterId::kCompileWaitForDispatcher);
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci  if (!job->is_running_on_background()) {
2081cb0ef41Sopenharmony_ci    if (job->state == Job::State::kPending) {
2091cb0ef41Sopenharmony_ci      DCHECK_EQ(std::count(pending_background_jobs_.begin(),
2101cb0ef41Sopenharmony_ci                           pending_background_jobs_.end(), job),
2111cb0ef41Sopenharmony_ci                1);
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci      // TODO(leszeks): Remove from pending jobs without walking the whole
2141cb0ef41Sopenharmony_ci      // vector.
2151cb0ef41Sopenharmony_ci      pending_background_jobs_.erase(
2161cb0ef41Sopenharmony_ci          std::remove(pending_background_jobs_.begin(),
2171cb0ef41Sopenharmony_ci                      pending_background_jobs_.end(), job));
2181cb0ef41Sopenharmony_ci      job->state = Job::State::kPendingToRunOnForeground;
2191cb0ef41Sopenharmony_ci      NotifyRemovedBackgroundJob(lock);
2201cb0ef41Sopenharmony_ci    } else {
2211cb0ef41Sopenharmony_ci      DCHECK_EQ(job->state, Job::State::kReadyToFinalize);
2221cb0ef41Sopenharmony_ci      DCHECK_EQ(
2231cb0ef41Sopenharmony_ci          std::count(finalizable_jobs_.begin(), finalizable_jobs_.end(), job),
2241cb0ef41Sopenharmony_ci          1);
2251cb0ef41Sopenharmony_ci
2261cb0ef41Sopenharmony_ci      // TODO(leszeks): Remove from finalizable jobs without walking the whole
2271cb0ef41Sopenharmony_ci      // vector.
2281cb0ef41Sopenharmony_ci      finalizable_jobs_.erase(
2291cb0ef41Sopenharmony_ci          std::remove(finalizable_jobs_.begin(), finalizable_jobs_.end(), job));
2301cb0ef41Sopenharmony_ci      job->state = Job::State::kFinalizingNow;
2311cb0ef41Sopenharmony_ci    }
2321cb0ef41Sopenharmony_ci    return;
2331cb0ef41Sopenharmony_ci  }
2341cb0ef41Sopenharmony_ci  DCHECK_NULL(main_thread_blocking_on_job_);
2351cb0ef41Sopenharmony_ci  main_thread_blocking_on_job_ = job;
2361cb0ef41Sopenharmony_ci  while (main_thread_blocking_on_job_ != nullptr) {
2371cb0ef41Sopenharmony_ci    main_thread_blocking_signal_.Wait(&mutex_);
2381cb0ef41Sopenharmony_ci  }
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ci  DCHECK_EQ(job->state, Job::State::kReadyToFinalize);
2411cb0ef41Sopenharmony_ci  DCHECK_EQ(std::count(finalizable_jobs_.begin(), finalizable_jobs_.end(), job),
2421cb0ef41Sopenharmony_ci            1);
2431cb0ef41Sopenharmony_ci
2441cb0ef41Sopenharmony_ci  // TODO(leszeks): Remove from finalizable jobs without walking the whole
2451cb0ef41Sopenharmony_ci  // vector.
2461cb0ef41Sopenharmony_ci  finalizable_jobs_.erase(
2471cb0ef41Sopenharmony_ci      std::remove(finalizable_jobs_.begin(), finalizable_jobs_.end(), job));
2481cb0ef41Sopenharmony_ci  job->state = Job::State::kFinalizingNow;
2491cb0ef41Sopenharmony_ci}
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_cibool LazyCompileDispatcher::FinishNow(Handle<SharedFunctionInfo> function) {
2521cb0ef41Sopenharmony_ci  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
2531cb0ef41Sopenharmony_ci               "V8.LazyCompilerDispatcherFinishNow");
2541cb0ef41Sopenharmony_ci  RCS_SCOPE(isolate_, RuntimeCallCounterId::kCompileFinishNowOnDispatcher);
2551cb0ef41Sopenharmony_ci  if (trace_compiler_dispatcher_) {
2561cb0ef41Sopenharmony_ci    PrintF("LazyCompileDispatcher: finishing ");
2571cb0ef41Sopenharmony_ci    function->ShortPrint();
2581cb0ef41Sopenharmony_ci    PrintF(" now\n");
2591cb0ef41Sopenharmony_ci  }
2601cb0ef41Sopenharmony_ci
2611cb0ef41Sopenharmony_ci  Job* job;
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  {
2641cb0ef41Sopenharmony_ci    base::MutexGuard lock(&mutex_);
2651cb0ef41Sopenharmony_ci    job = GetJobFor(function, lock);
2661cb0ef41Sopenharmony_ci    WaitForJobIfRunningOnBackground(job, lock);
2671cb0ef41Sopenharmony_ci  }
2681cb0ef41Sopenharmony_ci
2691cb0ef41Sopenharmony_ci  if (job->state == Job::State::kPendingToRunOnForeground) {
2701cb0ef41Sopenharmony_ci    job->task->RunOnMainThread(isolate_);
2711cb0ef41Sopenharmony_ci    job->state = Job::State::kFinalizingNow;
2721cb0ef41Sopenharmony_ci  }
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_ci  if (DEBUG_BOOL) {
2751cb0ef41Sopenharmony_ci    base::MutexGuard lock(&mutex_);
2761cb0ef41Sopenharmony_ci    DCHECK_EQ(std::count(pending_background_jobs_.begin(),
2771cb0ef41Sopenharmony_ci                         pending_background_jobs_.end(), job),
2781cb0ef41Sopenharmony_ci              0);
2791cb0ef41Sopenharmony_ci    DCHECK_EQ(
2801cb0ef41Sopenharmony_ci        std::count(finalizable_jobs_.begin(), finalizable_jobs_.end(), job), 0);
2811cb0ef41Sopenharmony_ci    DCHECK_EQ(job->state, Job::State::kFinalizingNow);
2821cb0ef41Sopenharmony_ci  }
2831cb0ef41Sopenharmony_ci
2841cb0ef41Sopenharmony_ci  bool success = Compiler::FinalizeBackgroundCompileTask(
2851cb0ef41Sopenharmony_ci      job->task.get(), isolate_, Compiler::KEEP_EXCEPTION);
2861cb0ef41Sopenharmony_ci  job->state = Job::State::kFinalized;
2871cb0ef41Sopenharmony_ci
2881cb0ef41Sopenharmony_ci  DCHECK_NE(success, isolate_->has_pending_exception());
2891cb0ef41Sopenharmony_ci  DeleteJob(job);
2901cb0ef41Sopenharmony_ci
2911cb0ef41Sopenharmony_ci  // Opportunistically finalize all other jobs for a maximum time of
2921cb0ef41Sopenharmony_ci  // kMaxOpportunisticFinalizeTimeMs.
2931cb0ef41Sopenharmony_ci  double deadline_in_seconds = platform_->MonotonicallyIncreasingTime() +
2941cb0ef41Sopenharmony_ci                               kMaxOpportunisticFinalizeTimeMs / 1000.0;
2951cb0ef41Sopenharmony_ci  while (deadline_in_seconds > platform_->MonotonicallyIncreasingTime()) {
2961cb0ef41Sopenharmony_ci    if (!FinalizeSingleJob()) break;
2971cb0ef41Sopenharmony_ci  }
2981cb0ef41Sopenharmony_ci
2991cb0ef41Sopenharmony_ci  return success;
3001cb0ef41Sopenharmony_ci}
3011cb0ef41Sopenharmony_ci
3021cb0ef41Sopenharmony_civoid LazyCompileDispatcher::AbortJob(Handle<SharedFunctionInfo> shared_info) {
3031cb0ef41Sopenharmony_ci  if (trace_compiler_dispatcher_) {
3041cb0ef41Sopenharmony_ci    PrintF("LazyCompileDispatcher: aborting job for ");
3051cb0ef41Sopenharmony_ci    shared_info->ShortPrint();
3061cb0ef41Sopenharmony_ci    PrintF("\n");
3071cb0ef41Sopenharmony_ci  }
3081cb0ef41Sopenharmony_ci  base::LockGuard<base::Mutex> lock(&mutex_);
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci  Job* job = GetJobFor(shared_info, lock);
3111cb0ef41Sopenharmony_ci  if (job->is_running_on_background()) {
3121cb0ef41Sopenharmony_ci    // Job is currently running on the background thread, wait until it's done
3131cb0ef41Sopenharmony_ci    // and remove job then.
3141cb0ef41Sopenharmony_ci    job->state = Job::State::kAbortRequested;
3151cb0ef41Sopenharmony_ci  } else {
3161cb0ef41Sopenharmony_ci    if (job->state == Job::State::kPending) {
3171cb0ef41Sopenharmony_ci      DCHECK_EQ(std::count(pending_background_jobs_.begin(),
3181cb0ef41Sopenharmony_ci                           pending_background_jobs_.end(), job),
3191cb0ef41Sopenharmony_ci                1);
3201cb0ef41Sopenharmony_ci
3211cb0ef41Sopenharmony_ci      pending_background_jobs_.erase(
3221cb0ef41Sopenharmony_ci          std::remove(pending_background_jobs_.begin(),
3231cb0ef41Sopenharmony_ci                      pending_background_jobs_.end(), job));
3241cb0ef41Sopenharmony_ci      job->state = Job::State::kAbortingNow;
3251cb0ef41Sopenharmony_ci      NotifyRemovedBackgroundJob(lock);
3261cb0ef41Sopenharmony_ci    } else if (job->state == Job::State::kReadyToFinalize) {
3271cb0ef41Sopenharmony_ci      DCHECK_EQ(
3281cb0ef41Sopenharmony_ci          std::count(finalizable_jobs_.begin(), finalizable_jobs_.end(), job),
3291cb0ef41Sopenharmony_ci          1);
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci      finalizable_jobs_.erase(
3321cb0ef41Sopenharmony_ci          std::remove(finalizable_jobs_.begin(), finalizable_jobs_.end(), job));
3331cb0ef41Sopenharmony_ci      job->state = Job::State::kAbortingNow;
3341cb0ef41Sopenharmony_ci    } else {
3351cb0ef41Sopenharmony_ci      UNREACHABLE();
3361cb0ef41Sopenharmony_ci    }
3371cb0ef41Sopenharmony_ci    job->task->AbortFunction();
3381cb0ef41Sopenharmony_ci    job->state = Job::State::kFinalized;
3391cb0ef41Sopenharmony_ci    DeleteJob(job, lock);
3401cb0ef41Sopenharmony_ci  }
3411cb0ef41Sopenharmony_ci}
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_civoid LazyCompileDispatcher::AbortAll() {
3441cb0ef41Sopenharmony_ci  idle_task_manager_->TryAbortAll();
3451cb0ef41Sopenharmony_ci  job_handle_->Cancel();
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_ci  {
3481cb0ef41Sopenharmony_ci    base::MutexGuard lock(&mutex_);
3491cb0ef41Sopenharmony_ci    for (Job* job : pending_background_jobs_) {
3501cb0ef41Sopenharmony_ci      job->task->AbortFunction();
3511cb0ef41Sopenharmony_ci      job->state = Job::State::kFinalized;
3521cb0ef41Sopenharmony_ci      DeleteJob(job, lock);
3531cb0ef41Sopenharmony_ci    }
3541cb0ef41Sopenharmony_ci    pending_background_jobs_.clear();
3551cb0ef41Sopenharmony_ci    for (Job* job : finalizable_jobs_) {
3561cb0ef41Sopenharmony_ci      job->task->AbortFunction();
3571cb0ef41Sopenharmony_ci      job->state = Job::State::kFinalized;
3581cb0ef41Sopenharmony_ci      DeleteJob(job, lock);
3591cb0ef41Sopenharmony_ci    }
3601cb0ef41Sopenharmony_ci    finalizable_jobs_.clear();
3611cb0ef41Sopenharmony_ci    for (Job* job : jobs_to_dispose_) {
3621cb0ef41Sopenharmony_ci      delete job;
3631cb0ef41Sopenharmony_ci    }
3641cb0ef41Sopenharmony_ci    jobs_to_dispose_.clear();
3651cb0ef41Sopenharmony_ci
3661cb0ef41Sopenharmony_ci    DCHECK_EQ(all_jobs_.size(), 0);
3671cb0ef41Sopenharmony_ci    num_jobs_for_background_ = 0;
3681cb0ef41Sopenharmony_ci    VerifyBackgroundTaskCount(lock);
3691cb0ef41Sopenharmony_ci  }
3701cb0ef41Sopenharmony_ci
3711cb0ef41Sopenharmony_ci  idle_task_manager_->CancelAndWait();
3721cb0ef41Sopenharmony_ci}
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ciLazyCompileDispatcher::Job* LazyCompileDispatcher::GetJobFor(
3751cb0ef41Sopenharmony_ci    Handle<SharedFunctionInfo> shared, const base::MutexGuard&) const {
3761cb0ef41Sopenharmony_ci  Object function_data = shared->function_data(kAcquireLoad);
3771cb0ef41Sopenharmony_ci  if (function_data.IsUncompiledDataWithPreparseDataAndJob()) {
3781cb0ef41Sopenharmony_ci    return reinterpret_cast<Job*>(
3791cb0ef41Sopenharmony_ci        UncompiledDataWithPreparseDataAndJob::cast(function_data).job());
3801cb0ef41Sopenharmony_ci  } else if (function_data.IsUncompiledDataWithoutPreparseDataWithJob()) {
3811cb0ef41Sopenharmony_ci    return reinterpret_cast<Job*>(
3821cb0ef41Sopenharmony_ci        UncompiledDataWithoutPreparseDataWithJob::cast(function_data).job());
3831cb0ef41Sopenharmony_ci  }
3841cb0ef41Sopenharmony_ci  return nullptr;
3851cb0ef41Sopenharmony_ci}
3861cb0ef41Sopenharmony_ci
3871cb0ef41Sopenharmony_civoid LazyCompileDispatcher::ScheduleIdleTaskFromAnyThread(
3881cb0ef41Sopenharmony_ci    const base::MutexGuard&) {
3891cb0ef41Sopenharmony_ci  if (!taskrunner_->IdleTasksEnabled()) return;
3901cb0ef41Sopenharmony_ci  if (idle_task_scheduled_) return;
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_ci  idle_task_scheduled_ = true;
3931cb0ef41Sopenharmony_ci  // TODO(leszeks): Using a full task manager for a single cancellable task is
3941cb0ef41Sopenharmony_ci  // overkill, we could probably do the cancelling ourselves.
3951cb0ef41Sopenharmony_ci  taskrunner_->PostIdleTask(MakeCancelableIdleTask(
3961cb0ef41Sopenharmony_ci      idle_task_manager_.get(),
3971cb0ef41Sopenharmony_ci      [this](double deadline_in_seconds) { DoIdleWork(deadline_in_seconds); }));
3981cb0ef41Sopenharmony_ci}
3991cb0ef41Sopenharmony_ci
4001cb0ef41Sopenharmony_civoid LazyCompileDispatcher::DoBackgroundWork(JobDelegate* delegate) {
4011cb0ef41Sopenharmony_ci  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
4021cb0ef41Sopenharmony_ci               "V8.LazyCompileDispatcherDoBackgroundWork");
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci  LocalIsolate isolate(isolate_, ThreadKind::kBackground);
4051cb0ef41Sopenharmony_ci  UnparkedScope unparked_scope(&isolate);
4061cb0ef41Sopenharmony_ci  LocalHandleScope handle_scope(&isolate);
4071cb0ef41Sopenharmony_ci
4081cb0ef41Sopenharmony_ci  ReusableUnoptimizedCompileState reusable_state(&isolate);
4091cb0ef41Sopenharmony_ci
4101cb0ef41Sopenharmony_ci  while (!delegate->ShouldYield()) {
4111cb0ef41Sopenharmony_ci    Job* job = nullptr;
4121cb0ef41Sopenharmony_ci    {
4131cb0ef41Sopenharmony_ci      base::MutexGuard lock(&mutex_);
4141cb0ef41Sopenharmony_ci
4151cb0ef41Sopenharmony_ci      if (pending_background_jobs_.empty()) break;
4161cb0ef41Sopenharmony_ci      job = pending_background_jobs_.back();
4171cb0ef41Sopenharmony_ci      pending_background_jobs_.pop_back();
4181cb0ef41Sopenharmony_ci      DCHECK_EQ(job->state, Job::State::kPending);
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ci      job->state = Job::State::kRunning;
4211cb0ef41Sopenharmony_ci    }
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ci    if (V8_UNLIKELY(block_for_testing_.Value())) {
4241cb0ef41Sopenharmony_ci      block_for_testing_.SetValue(false);
4251cb0ef41Sopenharmony_ci      semaphore_for_testing_.Wait();
4261cb0ef41Sopenharmony_ci    }
4271cb0ef41Sopenharmony_ci
4281cb0ef41Sopenharmony_ci    if (trace_compiler_dispatcher_) {
4291cb0ef41Sopenharmony_ci      PrintF("LazyCompileDispatcher: doing background work\n");
4301cb0ef41Sopenharmony_ci    }
4311cb0ef41Sopenharmony_ci
4321cb0ef41Sopenharmony_ci    job->task->Run(&isolate, &reusable_state);
4331cb0ef41Sopenharmony_ci
4341cb0ef41Sopenharmony_ci    {
4351cb0ef41Sopenharmony_ci      base::MutexGuard lock(&mutex_);
4361cb0ef41Sopenharmony_ci      if (job->state == Job::State::kRunning) {
4371cb0ef41Sopenharmony_ci        job->state = Job::State::kReadyToFinalize;
4381cb0ef41Sopenharmony_ci        // Schedule an idle task to finalize the compilation on the main thread
4391cb0ef41Sopenharmony_ci        // if the job has a shared function info registered.
4401cb0ef41Sopenharmony_ci      } else {
4411cb0ef41Sopenharmony_ci        DCHECK_EQ(job->state, Job::State::kAbortRequested);
4421cb0ef41Sopenharmony_ci        job->state = Job::State::kAborted;
4431cb0ef41Sopenharmony_ci      }
4441cb0ef41Sopenharmony_ci      finalizable_jobs_.push_back(job);
4451cb0ef41Sopenharmony_ci      NotifyRemovedBackgroundJob(lock);
4461cb0ef41Sopenharmony_ci
4471cb0ef41Sopenharmony_ci      if (main_thread_blocking_on_job_ == job) {
4481cb0ef41Sopenharmony_ci        main_thread_blocking_on_job_ = nullptr;
4491cb0ef41Sopenharmony_ci        main_thread_blocking_signal_.NotifyOne();
4501cb0ef41Sopenharmony_ci      } else {
4511cb0ef41Sopenharmony_ci        ScheduleIdleTaskFromAnyThread(lock);
4521cb0ef41Sopenharmony_ci      }
4531cb0ef41Sopenharmony_ci    }
4541cb0ef41Sopenharmony_ci  }
4551cb0ef41Sopenharmony_ci
4561cb0ef41Sopenharmony_ci  while (!delegate->ShouldYield()) {
4571cb0ef41Sopenharmony_ci    Job* job = nullptr;
4581cb0ef41Sopenharmony_ci    {
4591cb0ef41Sopenharmony_ci      base::MutexGuard lock(&mutex_);
4601cb0ef41Sopenharmony_ci      if (jobs_to_dispose_.empty()) break;
4611cb0ef41Sopenharmony_ci      job = jobs_to_dispose_.back();
4621cb0ef41Sopenharmony_ci      jobs_to_dispose_.pop_back();
4631cb0ef41Sopenharmony_ci      if (jobs_to_dispose_.empty()) {
4641cb0ef41Sopenharmony_ci        num_jobs_for_background_--;
4651cb0ef41Sopenharmony_ci      }
4661cb0ef41Sopenharmony_ci    }
4671cb0ef41Sopenharmony_ci    delete job;
4681cb0ef41Sopenharmony_ci  }
4691cb0ef41Sopenharmony_ci
4701cb0ef41Sopenharmony_ci  // Don't touch |this| anymore after this point, as it might have been
4711cb0ef41Sopenharmony_ci  // deleted.
4721cb0ef41Sopenharmony_ci}
4731cb0ef41Sopenharmony_ci
4741cb0ef41Sopenharmony_ciLazyCompileDispatcher::Job* LazyCompileDispatcher::PopSingleFinalizeJob() {
4751cb0ef41Sopenharmony_ci  base::MutexGuard lock(&mutex_);
4761cb0ef41Sopenharmony_ci
4771cb0ef41Sopenharmony_ci  if (finalizable_jobs_.empty()) return nullptr;
4781cb0ef41Sopenharmony_ci
4791cb0ef41Sopenharmony_ci  Job* job = finalizable_jobs_.back();
4801cb0ef41Sopenharmony_ci  finalizable_jobs_.pop_back();
4811cb0ef41Sopenharmony_ci  DCHECK(job->state == Job::State::kReadyToFinalize ||
4821cb0ef41Sopenharmony_ci         job->state == Job::State::kAborted);
4831cb0ef41Sopenharmony_ci  if (job->state == Job::State::kReadyToFinalize) {
4841cb0ef41Sopenharmony_ci    job->state = Job::State::kFinalizingNow;
4851cb0ef41Sopenharmony_ci  } else {
4861cb0ef41Sopenharmony_ci    DCHECK_EQ(job->state, Job::State::kAborted);
4871cb0ef41Sopenharmony_ci    job->state = Job::State::kAbortingNow;
4881cb0ef41Sopenharmony_ci  }
4891cb0ef41Sopenharmony_ci  return job;
4901cb0ef41Sopenharmony_ci}
4911cb0ef41Sopenharmony_ci
4921cb0ef41Sopenharmony_cibool LazyCompileDispatcher::FinalizeSingleJob() {
4931cb0ef41Sopenharmony_ci  Job* job = PopSingleFinalizeJob();
4941cb0ef41Sopenharmony_ci  if (job == nullptr) return false;
4951cb0ef41Sopenharmony_ci
4961cb0ef41Sopenharmony_ci  if (trace_compiler_dispatcher_) {
4971cb0ef41Sopenharmony_ci    PrintF("LazyCompileDispatcher: idle finalizing job\n");
4981cb0ef41Sopenharmony_ci  }
4991cb0ef41Sopenharmony_ci
5001cb0ef41Sopenharmony_ci  if (job->state == Job::State::kFinalizingNow) {
5011cb0ef41Sopenharmony_ci    HandleScope scope(isolate_);
5021cb0ef41Sopenharmony_ci    Compiler::FinalizeBackgroundCompileTask(job->task.get(), isolate_,
5031cb0ef41Sopenharmony_ci                                            Compiler::CLEAR_EXCEPTION);
5041cb0ef41Sopenharmony_ci  } else {
5051cb0ef41Sopenharmony_ci    DCHECK_EQ(job->state, Job::State::kAbortingNow);
5061cb0ef41Sopenharmony_ci    job->task->AbortFunction();
5071cb0ef41Sopenharmony_ci  }
5081cb0ef41Sopenharmony_ci  job->state = Job::State::kFinalized;
5091cb0ef41Sopenharmony_ci  DeleteJob(job);
5101cb0ef41Sopenharmony_ci  return true;
5111cb0ef41Sopenharmony_ci}
5121cb0ef41Sopenharmony_ci
5131cb0ef41Sopenharmony_civoid LazyCompileDispatcher::DoIdleWork(double deadline_in_seconds) {
5141cb0ef41Sopenharmony_ci  TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"),
5151cb0ef41Sopenharmony_ci               "V8.LazyCompilerDispatcherDoIdleWork");
5161cb0ef41Sopenharmony_ci  {
5171cb0ef41Sopenharmony_ci    base::MutexGuard lock(&mutex_);
5181cb0ef41Sopenharmony_ci    idle_task_scheduled_ = false;
5191cb0ef41Sopenharmony_ci  }
5201cb0ef41Sopenharmony_ci
5211cb0ef41Sopenharmony_ci  if (trace_compiler_dispatcher_) {
5221cb0ef41Sopenharmony_ci    PrintF("LazyCompileDispatcher: received %0.1lfms of idle time\n",
5231cb0ef41Sopenharmony_ci           (deadline_in_seconds - platform_->MonotonicallyIncreasingTime()) *
5241cb0ef41Sopenharmony_ci               static_cast<double>(base::Time::kMillisecondsPerSecond));
5251cb0ef41Sopenharmony_ci  }
5261cb0ef41Sopenharmony_ci  while (deadline_in_seconds > platform_->MonotonicallyIncreasingTime()) {
5271cb0ef41Sopenharmony_ci    // Find a job which is pending finalization and has a shared function info
5281cb0ef41Sopenharmony_ci    auto there_was_a_job = FinalizeSingleJob();
5291cb0ef41Sopenharmony_ci    if (!there_was_a_job) return;
5301cb0ef41Sopenharmony_ci  }
5311cb0ef41Sopenharmony_ci
5321cb0ef41Sopenharmony_ci  // We didn't return above so there still might be jobs to finalize.
5331cb0ef41Sopenharmony_ci  {
5341cb0ef41Sopenharmony_ci    base::MutexGuard lock(&mutex_);
5351cb0ef41Sopenharmony_ci    ScheduleIdleTaskFromAnyThread(lock);
5361cb0ef41Sopenharmony_ci  }
5371cb0ef41Sopenharmony_ci}
5381cb0ef41Sopenharmony_ci
5391cb0ef41Sopenharmony_civoid LazyCompileDispatcher::DeleteJob(Job* job) {
5401cb0ef41Sopenharmony_ci  DCHECK(job->state == Job::State::kFinalized);
5411cb0ef41Sopenharmony_ci  base::MutexGuard lock(&mutex_);
5421cb0ef41Sopenharmony_ci  DeleteJob(job, lock);
5431cb0ef41Sopenharmony_ci}
5441cb0ef41Sopenharmony_ci
5451cb0ef41Sopenharmony_civoid LazyCompileDispatcher::DeleteJob(Job* job, const base::MutexGuard&) {
5461cb0ef41Sopenharmony_ci  DCHECK(job->state == Job::State::kFinalized);
5471cb0ef41Sopenharmony_ci#ifdef DEBUG
5481cb0ef41Sopenharmony_ci  all_jobs_.erase(job);
5491cb0ef41Sopenharmony_ci#endif
5501cb0ef41Sopenharmony_ci  jobs_to_dispose_.push_back(job);
5511cb0ef41Sopenharmony_ci  if (jobs_to_dispose_.size() == 1) {
5521cb0ef41Sopenharmony_ci    num_jobs_for_background_++;
5531cb0ef41Sopenharmony_ci  }
5541cb0ef41Sopenharmony_ci}
5551cb0ef41Sopenharmony_ci
5561cb0ef41Sopenharmony_ci#ifdef DEBUG
5571cb0ef41Sopenharmony_civoid LazyCompileDispatcher::VerifyBackgroundTaskCount(const base::MutexGuard&) {
5581cb0ef41Sopenharmony_ci  size_t pending_jobs = 0;
5591cb0ef41Sopenharmony_ci  size_t running_jobs = 0;
5601cb0ef41Sopenharmony_ci  size_t finalizable_jobs = 0;
5611cb0ef41Sopenharmony_ci
5621cb0ef41Sopenharmony_ci  for (Job* job : all_jobs_) {
5631cb0ef41Sopenharmony_ci    switch (job->state) {
5641cb0ef41Sopenharmony_ci      case Job::State::kPending:
5651cb0ef41Sopenharmony_ci        pending_jobs++;
5661cb0ef41Sopenharmony_ci        break;
5671cb0ef41Sopenharmony_ci      case Job::State::kRunning:
5681cb0ef41Sopenharmony_ci      case Job::State::kAbortRequested:
5691cb0ef41Sopenharmony_ci        running_jobs++;
5701cb0ef41Sopenharmony_ci        break;
5711cb0ef41Sopenharmony_ci      case Job::State::kReadyToFinalize:
5721cb0ef41Sopenharmony_ci      case Job::State::kAborted:
5731cb0ef41Sopenharmony_ci        finalizable_jobs++;
5741cb0ef41Sopenharmony_ci        break;
5751cb0ef41Sopenharmony_ci      case Job::State::kPendingToRunOnForeground:
5761cb0ef41Sopenharmony_ci      case Job::State::kFinalizingNow:
5771cb0ef41Sopenharmony_ci      case Job::State::kAbortingNow:
5781cb0ef41Sopenharmony_ci      case Job::State::kFinalized:
5791cb0ef41Sopenharmony_ci        // Ignore.
5801cb0ef41Sopenharmony_ci        break;
5811cb0ef41Sopenharmony_ci    }
5821cb0ef41Sopenharmony_ci  }
5831cb0ef41Sopenharmony_ci
5841cb0ef41Sopenharmony_ci  CHECK_EQ(pending_background_jobs_.size(), pending_jobs);
5851cb0ef41Sopenharmony_ci  CHECK_EQ(finalizable_jobs_.size(), finalizable_jobs);
5861cb0ef41Sopenharmony_ci  CHECK_EQ(num_jobs_for_background_.load(),
5871cb0ef41Sopenharmony_ci           pending_jobs + running_jobs + (jobs_to_dispose_.empty() ? 0 : 1));
5881cb0ef41Sopenharmony_ci}
5891cb0ef41Sopenharmony_ci#endif
5901cb0ef41Sopenharmony_ci
5911cb0ef41Sopenharmony_ci}  // namespace internal
5921cb0ef41Sopenharmony_ci}  // namespace v8
593