• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/maglev/maglev-concurrent-dispatcher.h"
6 
7 #include "src/codegen/compiler.h"
8 #include "src/compiler/compilation-dependencies.h"
9 #include "src/compiler/js-heap-broker.h"
10 #include "src/execution/isolate.h"
11 #include "src/flags/flags.h"
12 #include "src/handles/persistent-handles.h"
13 #include "src/maglev/maglev-compilation-info.h"
14 #include "src/maglev/maglev-compiler.h"
15 #include "src/maglev/maglev-graph-labeller.h"
16 #include "src/objects/js-function-inl.h"
17 #include "src/utils/identity-map.h"
18 #include "src/utils/locked-queue-inl.h"
19 
20 namespace v8 {
21 namespace internal {
22 
23 namespace compiler {
24 
AttachLocalIsolateForMaglev(maglev::MaglevCompilationInfo * info,LocalIsolate * local_isolate)25 void JSHeapBroker::AttachLocalIsolateForMaglev(
26     maglev::MaglevCompilationInfo* info, LocalIsolate* local_isolate) {
27   set_canonical_handles(info->DetachCanonicalHandles());
28   DCHECK_NULL(local_isolate_);
29   local_isolate_ = local_isolate;
30   DCHECK_NOT_NULL(local_isolate_);
31   local_isolate_->heap()->AttachPersistentHandles(
32       info->DetachPersistentHandles());
33 }
34 
DetachLocalIsolateForMaglev(maglev::MaglevCompilationInfo * info)35 void JSHeapBroker::DetachLocalIsolateForMaglev(
36     maglev::MaglevCompilationInfo* info) {
37   DCHECK_NULL(ph_);
38   DCHECK_NOT_NULL(local_isolate_);
39   std::unique_ptr<PersistentHandles> ph =
40       local_isolate_->heap()->DetachPersistentHandles();
41   local_isolate_ = nullptr;
42   info->set_canonical_handles(DetachCanonicalHandles());
43   info->set_persistent_handles(std::move(ph));
44 }
45 
46 }  // namespace compiler
47 
48 namespace maglev {
49 
50 namespace {
51 
52 constexpr char kMaglevCompilerName[] = "Maglev";
53 
54 // LocalIsolateScope encapsulates the phase where persistent handles are
55 // attached to the LocalHeap inside {local_isolate}.
56 class V8_NODISCARD LocalIsolateScope final {
57  public:
LocalIsolateScope(MaglevCompilationInfo * info,LocalIsolate * local_isolate)58   explicit LocalIsolateScope(MaglevCompilationInfo* info,
59                              LocalIsolate* local_isolate)
60       : info_(info) {
61     info_->broker()->AttachLocalIsolateForMaglev(info_, local_isolate);
62   }
63 
~LocalIsolateScope()64   ~LocalIsolateScope() { info_->broker()->DetachLocalIsolateForMaglev(info_); }
65 
66  private:
67   MaglevCompilationInfo* const info_;
68 };
69 
70 }  // namespace
71 
zone() const72 Zone* ExportedMaglevCompilationInfo::zone() const { return info_->zone(); }
73 
set_canonical_handles(std::unique_ptr<CanonicalHandlesMap> && canonical_handles)74 void ExportedMaglevCompilationInfo::set_canonical_handles(
75     std::unique_ptr<CanonicalHandlesMap>&& canonical_handles) {
76   info_->set_canonical_handles(std::move(canonical_handles));
77 }
78 
79 // static
New(Isolate * isolate,Handle<JSFunction> function)80 std::unique_ptr<MaglevCompilationJob> MaglevCompilationJob::New(
81     Isolate* isolate, Handle<JSFunction> function) {
82   auto info = maglev::MaglevCompilationInfo::New(isolate, function);
83   return std::unique_ptr<MaglevCompilationJob>(
84       new MaglevCompilationJob(std::move(info)));
85 }
86 
MaglevCompilationJob(std::unique_ptr<MaglevCompilationInfo> && info)87 MaglevCompilationJob::MaglevCompilationJob(
88     std::unique_ptr<MaglevCompilationInfo>&& info)
89     : OptimizedCompilationJob(kMaglevCompilerName, State::kReadyToPrepare),
90       info_(std::move(info)) {
91   DCHECK(FLAG_maglev);
92 }
93 
94 MaglevCompilationJob::~MaglevCompilationJob() = default;
95 
PrepareJobImpl(Isolate * isolate)96 CompilationJob::Status MaglevCompilationJob::PrepareJobImpl(Isolate* isolate) {
97   // TODO(v8:7700): Actual return codes.
98   return CompilationJob::SUCCEEDED;
99 }
100 
ExecuteJobImpl(RuntimeCallStats * stats,LocalIsolate * local_isolate)101 CompilationJob::Status MaglevCompilationJob::ExecuteJobImpl(
102     RuntimeCallStats* stats, LocalIsolate* local_isolate) {
103   LocalIsolateScope scope{info(), local_isolate};
104   maglev::MaglevCompiler::Compile(local_isolate,
105                                   info()->toplevel_compilation_unit());
106   // TODO(v8:7700): Actual return codes.
107   return CompilationJob::SUCCEEDED;
108 }
109 
FinalizeJobImpl(Isolate * isolate)110 CompilationJob::Status MaglevCompilationJob::FinalizeJobImpl(Isolate* isolate) {
111   Handle<CodeT> codet;
112   if (!maglev::MaglevCompiler::GenerateCode(info()->toplevel_compilation_unit())
113            .ToHandle(&codet)) {
114     return CompilationJob::FAILED;
115   }
116   info()->function()->set_code(*codet);
117   return CompilationJob::SUCCEEDED;
118 }
119 
function() const120 Handle<JSFunction> MaglevCompilationJob::function() const {
121   return info_->function();
122 }
123 
124 // The JobTask is posted to V8::GetCurrentPlatform(). It's responsible for
125 // processing the incoming queue on a worker thread.
126 class MaglevConcurrentDispatcher::JobTask final : public v8::JobTask {
127  public:
JobTask(MaglevConcurrentDispatcher * dispatcher)128   explicit JobTask(MaglevConcurrentDispatcher* dispatcher)
129       : dispatcher_(dispatcher) {}
130 
Run(JobDelegate * delegate)131   void Run(JobDelegate* delegate) override {
132     LocalIsolate local_isolate(isolate(), ThreadKind::kBackground);
133     DCHECK(local_isolate.heap()->IsParked());
134 
135     while (!incoming_queue()->IsEmpty() && !delegate->ShouldYield()) {
136       std::unique_ptr<MaglevCompilationJob> job;
137       if (!incoming_queue()->Dequeue(&job)) break;
138       DCHECK_NOT_NULL(job);
139       RuntimeCallStats* rcs = nullptr;  // TODO(v8:7700): Implement.
140       CompilationJob::Status status = job->ExecuteJob(rcs, &local_isolate);
141       CHECK_EQ(status, CompilationJob::SUCCEEDED);
142       outgoing_queue()->Enqueue(std::move(job));
143     }
144     isolate()->stack_guard()->RequestInstallMaglevCode();
145   }
146 
GetMaxConcurrency(size_t) const147   size_t GetMaxConcurrency(size_t) const override {
148     return incoming_queue()->size();
149   }
150 
151  private:
isolate() const152   Isolate* isolate() const { return dispatcher_->isolate_; }
incoming_queue() const153   QueueT* incoming_queue() const { return &dispatcher_->incoming_queue_; }
outgoing_queue() const154   QueueT* outgoing_queue() const { return &dispatcher_->outgoing_queue_; }
155 
156   MaglevConcurrentDispatcher* const dispatcher_;
157   const Handle<JSFunction> function_;
158 };
159 
MaglevConcurrentDispatcher(Isolate * isolate)160 MaglevConcurrentDispatcher::MaglevConcurrentDispatcher(Isolate* isolate)
161     : isolate_(isolate) {
162   if (FLAG_concurrent_recompilation && FLAG_maglev) {
163     job_handle_ = V8::GetCurrentPlatform()->PostJob(
164         TaskPriority::kUserVisible, std::make_unique<JobTask>(this));
165     DCHECK(is_enabled());
166   } else {
167     DCHECK(!is_enabled());
168   }
169 }
170 
~MaglevConcurrentDispatcher()171 MaglevConcurrentDispatcher::~MaglevConcurrentDispatcher() {
172   if (is_enabled() && job_handle_->IsValid()) {
173     // Wait for the job handle to complete, so that we know the queue
174     // pointers are safe.
175     job_handle_->Cancel();
176   }
177 }
178 
EnqueueJob(std::unique_ptr<MaglevCompilationJob> && job)179 void MaglevConcurrentDispatcher::EnqueueJob(
180     std::unique_ptr<MaglevCompilationJob>&& job) {
181   DCHECK(is_enabled());
182   // TODO(v8:7700): RCS.
183   // RCS_SCOPE(isolate_, RuntimeCallCounterId::kCompileMaglev);
184   incoming_queue_.Enqueue(std::move(job));
185   job_handle_->NotifyConcurrencyIncrease();
186 }
187 
FinalizeFinishedJobs()188 void MaglevConcurrentDispatcher::FinalizeFinishedJobs() {
189   HandleScope handle_scope(isolate_);
190   while (!outgoing_queue_.IsEmpty()) {
191     std::unique_ptr<MaglevCompilationJob> job;
192     outgoing_queue_.Dequeue(&job);
193     CompilationJob::Status status = job->FinalizeJob(isolate_);
194     // TODO(v8:7700): Use the result and check if job succeed
195     // when all the bytecodes are implemented.
196     if (status == CompilationJob::SUCCEEDED) {
197       Compiler::FinalizeMaglevCompilationJob(job.get(), isolate_);
198     }
199   }
200 }
201 
202 }  // namespace maglev
203 }  // namespace internal
204 }  // namespace v8
205