11cb0ef41Sopenharmony_ci// Copyright 2022 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/maglev/maglev-concurrent-dispatcher.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include "src/codegen/compiler.h"
81cb0ef41Sopenharmony_ci#include "src/compiler/compilation-dependencies.h"
91cb0ef41Sopenharmony_ci#include "src/compiler/js-heap-broker.h"
101cb0ef41Sopenharmony_ci#include "src/execution/isolate.h"
111cb0ef41Sopenharmony_ci#include "src/flags/flags.h"
121cb0ef41Sopenharmony_ci#include "src/handles/persistent-handles.h"
131cb0ef41Sopenharmony_ci#include "src/maglev/maglev-compilation-info.h"
141cb0ef41Sopenharmony_ci#include "src/maglev/maglev-compiler.h"
151cb0ef41Sopenharmony_ci#include "src/maglev/maglev-graph-labeller.h"
161cb0ef41Sopenharmony_ci#include "src/objects/js-function-inl.h"
171cb0ef41Sopenharmony_ci#include "src/utils/identity-map.h"
181cb0ef41Sopenharmony_ci#include "src/utils/locked-queue-inl.h"
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_cinamespace v8 {
211cb0ef41Sopenharmony_cinamespace internal {
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_cinamespace compiler {
241cb0ef41Sopenharmony_ci
251cb0ef41Sopenharmony_civoid JSHeapBroker::AttachLocalIsolateForMaglev(
261cb0ef41Sopenharmony_ci    maglev::MaglevCompilationInfo* info, LocalIsolate* local_isolate) {
271cb0ef41Sopenharmony_ci  set_canonical_handles(info->DetachCanonicalHandles());
281cb0ef41Sopenharmony_ci  DCHECK_NULL(local_isolate_);
291cb0ef41Sopenharmony_ci  local_isolate_ = local_isolate;
301cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(local_isolate_);
311cb0ef41Sopenharmony_ci  local_isolate_->heap()->AttachPersistentHandles(
321cb0ef41Sopenharmony_ci      info->DetachPersistentHandles());
331cb0ef41Sopenharmony_ci}
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_civoid JSHeapBroker::DetachLocalIsolateForMaglev(
361cb0ef41Sopenharmony_ci    maglev::MaglevCompilationInfo* info) {
371cb0ef41Sopenharmony_ci  DCHECK_NULL(ph_);
381cb0ef41Sopenharmony_ci  DCHECK_NOT_NULL(local_isolate_);
391cb0ef41Sopenharmony_ci  std::unique_ptr<PersistentHandles> ph =
401cb0ef41Sopenharmony_ci      local_isolate_->heap()->DetachPersistentHandles();
411cb0ef41Sopenharmony_ci  local_isolate_ = nullptr;
421cb0ef41Sopenharmony_ci  info->set_canonical_handles(DetachCanonicalHandles());
431cb0ef41Sopenharmony_ci  info->set_persistent_handles(std::move(ph));
441cb0ef41Sopenharmony_ci}
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci}  // namespace compiler
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_cinamespace maglev {
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_cinamespace {
511cb0ef41Sopenharmony_ci
521cb0ef41Sopenharmony_ciconstexpr char kMaglevCompilerName[] = "Maglev";
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci// LocalIsolateScope encapsulates the phase where persistent handles are
551cb0ef41Sopenharmony_ci// attached to the LocalHeap inside {local_isolate}.
561cb0ef41Sopenharmony_ciclass V8_NODISCARD LocalIsolateScope final {
571cb0ef41Sopenharmony_ci public:
581cb0ef41Sopenharmony_ci  explicit LocalIsolateScope(MaglevCompilationInfo* info,
591cb0ef41Sopenharmony_ci                             LocalIsolate* local_isolate)
601cb0ef41Sopenharmony_ci      : info_(info) {
611cb0ef41Sopenharmony_ci    info_->broker()->AttachLocalIsolateForMaglev(info_, local_isolate);
621cb0ef41Sopenharmony_ci  }
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  ~LocalIsolateScope() { info_->broker()->DetachLocalIsolateForMaglev(info_); }
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci private:
671cb0ef41Sopenharmony_ci  MaglevCompilationInfo* const info_;
681cb0ef41Sopenharmony_ci};
691cb0ef41Sopenharmony_ci
701cb0ef41Sopenharmony_ci}  // namespace
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ciZone* ExportedMaglevCompilationInfo::zone() const { return info_->zone(); }
731cb0ef41Sopenharmony_ci
741cb0ef41Sopenharmony_civoid ExportedMaglevCompilationInfo::set_canonical_handles(
751cb0ef41Sopenharmony_ci    std::unique_ptr<CanonicalHandlesMap>&& canonical_handles) {
761cb0ef41Sopenharmony_ci  info_->set_canonical_handles(std::move(canonical_handles));
771cb0ef41Sopenharmony_ci}
781cb0ef41Sopenharmony_ci
791cb0ef41Sopenharmony_ci// static
801cb0ef41Sopenharmony_cistd::unique_ptr<MaglevCompilationJob> MaglevCompilationJob::New(
811cb0ef41Sopenharmony_ci    Isolate* isolate, Handle<JSFunction> function) {
821cb0ef41Sopenharmony_ci  auto info = maglev::MaglevCompilationInfo::New(isolate, function);
831cb0ef41Sopenharmony_ci  return std::unique_ptr<MaglevCompilationJob>(
841cb0ef41Sopenharmony_ci      new MaglevCompilationJob(std::move(info)));
851cb0ef41Sopenharmony_ci}
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ciMaglevCompilationJob::MaglevCompilationJob(
881cb0ef41Sopenharmony_ci    std::unique_ptr<MaglevCompilationInfo>&& info)
891cb0ef41Sopenharmony_ci    : OptimizedCompilationJob(kMaglevCompilerName, State::kReadyToPrepare),
901cb0ef41Sopenharmony_ci      info_(std::move(info)) {
911cb0ef41Sopenharmony_ci  DCHECK(FLAG_maglev);
921cb0ef41Sopenharmony_ci}
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ciMaglevCompilationJob::~MaglevCompilationJob() = default;
951cb0ef41Sopenharmony_ci
961cb0ef41Sopenharmony_ciCompilationJob::Status MaglevCompilationJob::PrepareJobImpl(Isolate* isolate) {
971cb0ef41Sopenharmony_ci  // TODO(v8:7700): Actual return codes.
981cb0ef41Sopenharmony_ci  return CompilationJob::SUCCEEDED;
991cb0ef41Sopenharmony_ci}
1001cb0ef41Sopenharmony_ci
1011cb0ef41Sopenharmony_ciCompilationJob::Status MaglevCompilationJob::ExecuteJobImpl(
1021cb0ef41Sopenharmony_ci    RuntimeCallStats* stats, LocalIsolate* local_isolate) {
1031cb0ef41Sopenharmony_ci  LocalIsolateScope scope{info(), local_isolate};
1041cb0ef41Sopenharmony_ci  maglev::MaglevCompiler::Compile(local_isolate,
1051cb0ef41Sopenharmony_ci                                  info()->toplevel_compilation_unit());
1061cb0ef41Sopenharmony_ci  // TODO(v8:7700): Actual return codes.
1071cb0ef41Sopenharmony_ci  return CompilationJob::SUCCEEDED;
1081cb0ef41Sopenharmony_ci}
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ciCompilationJob::Status MaglevCompilationJob::FinalizeJobImpl(Isolate* isolate) {
1111cb0ef41Sopenharmony_ci  Handle<CodeT> codet;
1121cb0ef41Sopenharmony_ci  if (!maglev::MaglevCompiler::GenerateCode(info()->toplevel_compilation_unit())
1131cb0ef41Sopenharmony_ci           .ToHandle(&codet)) {
1141cb0ef41Sopenharmony_ci    return CompilationJob::FAILED;
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci  info()->function()->set_code(*codet);
1171cb0ef41Sopenharmony_ci  return CompilationJob::SUCCEEDED;
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ciHandle<JSFunction> MaglevCompilationJob::function() const {
1211cb0ef41Sopenharmony_ci  return info_->function();
1221cb0ef41Sopenharmony_ci}
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_ci// The JobTask is posted to V8::GetCurrentPlatform(). It's responsible for
1251cb0ef41Sopenharmony_ci// processing the incoming queue on a worker thread.
1261cb0ef41Sopenharmony_ciclass MaglevConcurrentDispatcher::JobTask final : public v8::JobTask {
1271cb0ef41Sopenharmony_ci public:
1281cb0ef41Sopenharmony_ci  explicit JobTask(MaglevConcurrentDispatcher* dispatcher)
1291cb0ef41Sopenharmony_ci      : dispatcher_(dispatcher) {}
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci  void Run(JobDelegate* delegate) override {
1321cb0ef41Sopenharmony_ci    LocalIsolate local_isolate(isolate(), ThreadKind::kBackground);
1331cb0ef41Sopenharmony_ci    DCHECK(local_isolate.heap()->IsParked());
1341cb0ef41Sopenharmony_ci
1351cb0ef41Sopenharmony_ci    while (!incoming_queue()->IsEmpty() && !delegate->ShouldYield()) {
1361cb0ef41Sopenharmony_ci      std::unique_ptr<MaglevCompilationJob> job;
1371cb0ef41Sopenharmony_ci      if (!incoming_queue()->Dequeue(&job)) break;
1381cb0ef41Sopenharmony_ci      DCHECK_NOT_NULL(job);
1391cb0ef41Sopenharmony_ci      RuntimeCallStats* rcs = nullptr;  // TODO(v8:7700): Implement.
1401cb0ef41Sopenharmony_ci      CompilationJob::Status status = job->ExecuteJob(rcs, &local_isolate);
1411cb0ef41Sopenharmony_ci      CHECK_EQ(status, CompilationJob::SUCCEEDED);
1421cb0ef41Sopenharmony_ci      outgoing_queue()->Enqueue(std::move(job));
1431cb0ef41Sopenharmony_ci    }
1441cb0ef41Sopenharmony_ci    isolate()->stack_guard()->RequestInstallMaglevCode();
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci
1471cb0ef41Sopenharmony_ci  size_t GetMaxConcurrency(size_t) const override {
1481cb0ef41Sopenharmony_ci    return incoming_queue()->size();
1491cb0ef41Sopenharmony_ci  }
1501cb0ef41Sopenharmony_ci
1511cb0ef41Sopenharmony_ci private:
1521cb0ef41Sopenharmony_ci  Isolate* isolate() const { return dispatcher_->isolate_; }
1531cb0ef41Sopenharmony_ci  QueueT* incoming_queue() const { return &dispatcher_->incoming_queue_; }
1541cb0ef41Sopenharmony_ci  QueueT* outgoing_queue() const { return &dispatcher_->outgoing_queue_; }
1551cb0ef41Sopenharmony_ci
1561cb0ef41Sopenharmony_ci  MaglevConcurrentDispatcher* const dispatcher_;
1571cb0ef41Sopenharmony_ci  const Handle<JSFunction> function_;
1581cb0ef41Sopenharmony_ci};
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ciMaglevConcurrentDispatcher::MaglevConcurrentDispatcher(Isolate* isolate)
1611cb0ef41Sopenharmony_ci    : isolate_(isolate) {
1621cb0ef41Sopenharmony_ci  if (FLAG_concurrent_recompilation && FLAG_maglev) {
1631cb0ef41Sopenharmony_ci    job_handle_ = V8::GetCurrentPlatform()->PostJob(
1641cb0ef41Sopenharmony_ci        TaskPriority::kUserVisible, std::make_unique<JobTask>(this));
1651cb0ef41Sopenharmony_ci    DCHECK(is_enabled());
1661cb0ef41Sopenharmony_ci  } else {
1671cb0ef41Sopenharmony_ci    DCHECK(!is_enabled());
1681cb0ef41Sopenharmony_ci  }
1691cb0ef41Sopenharmony_ci}
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ciMaglevConcurrentDispatcher::~MaglevConcurrentDispatcher() {
1721cb0ef41Sopenharmony_ci  if (is_enabled() && job_handle_->IsValid()) {
1731cb0ef41Sopenharmony_ci    // Wait for the job handle to complete, so that we know the queue
1741cb0ef41Sopenharmony_ci    // pointers are safe.
1751cb0ef41Sopenharmony_ci    job_handle_->Cancel();
1761cb0ef41Sopenharmony_ci  }
1771cb0ef41Sopenharmony_ci}
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_civoid MaglevConcurrentDispatcher::EnqueueJob(
1801cb0ef41Sopenharmony_ci    std::unique_ptr<MaglevCompilationJob>&& job) {
1811cb0ef41Sopenharmony_ci  DCHECK(is_enabled());
1821cb0ef41Sopenharmony_ci  // TODO(v8:7700): RCS.
1831cb0ef41Sopenharmony_ci  // RCS_SCOPE(isolate_, RuntimeCallCounterId::kCompileMaglev);
1841cb0ef41Sopenharmony_ci  incoming_queue_.Enqueue(std::move(job));
1851cb0ef41Sopenharmony_ci  job_handle_->NotifyConcurrencyIncrease();
1861cb0ef41Sopenharmony_ci}
1871cb0ef41Sopenharmony_ci
1881cb0ef41Sopenharmony_civoid MaglevConcurrentDispatcher::FinalizeFinishedJobs() {
1891cb0ef41Sopenharmony_ci  HandleScope handle_scope(isolate_);
1901cb0ef41Sopenharmony_ci  while (!outgoing_queue_.IsEmpty()) {
1911cb0ef41Sopenharmony_ci    std::unique_ptr<MaglevCompilationJob> job;
1921cb0ef41Sopenharmony_ci    outgoing_queue_.Dequeue(&job);
1931cb0ef41Sopenharmony_ci    CompilationJob::Status status = job->FinalizeJob(isolate_);
1941cb0ef41Sopenharmony_ci    // TODO(v8:7700): Use the result and check if job succeed
1951cb0ef41Sopenharmony_ci    // when all the bytecodes are implemented.
1961cb0ef41Sopenharmony_ci    if (status == CompilationJob::SUCCEEDED) {
1971cb0ef41Sopenharmony_ci      Compiler::FinalizeMaglevCompilationJob(job.get(), isolate_);
1981cb0ef41Sopenharmony_ci    }
1991cb0ef41Sopenharmony_ci  }
2001cb0ef41Sopenharmony_ci}
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci}  // namespace maglev
2031cb0ef41Sopenharmony_ci}  // namespace internal
2041cb0ef41Sopenharmony_ci}  // namespace v8
205