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