v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
baseline-batch-compiler.cc
Go to the documentation of this file.
1// Copyright 2021 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
6
7#include <algorithm>
8
9#include "src/base/fpu.h"
15#include "src/heap/heap-inl.h"
21
22namespace v8 {
23namespace internal {
24namespace baseline {
25
27 Isolate* isolate) {
28 return !shared->HasBaselineCode() && CanCompileWithBaseline(isolate, shared);
29}
30
32 public:
35 : shared_function_info_(handles->NewHandle(sfi)),
36 bytecode_(handles->NewHandle(sfi->GetBytecodeArray(isolate))) {
37 DCHECK(sfi->is_compiled());
38 shared_function_info_->set_is_sparkplug_compiling(true);
39 }
40
43
44 // Executed in the background thread.
45 void Compile(LocalIsolate* local_isolate) {
46 RCS_SCOPE(local_isolate, RuntimeCallCounterId::kCompileBackgroundBaseline);
47 base::ScopedTimer timer(v8_flags.log_function_events ? &time_taken_
48 : nullptr);
49 BaselineCompiler compiler(local_isolate, shared_function_info_, bytecode_);
50 compiler.GenerateCode();
52 local_isolate->heap()->NewPersistentMaybeHandle(compiler.Build());
53 }
54
55 // Executed in the main thread.
56 void Install(Isolate* isolate) {
57 shared_function_info_->set_is_sparkplug_compiling(false);
59 if (!maybe_code_.ToHandle(&code)) return;
60 if (v8_flags.print_code) {
61 Print(*code);
62 }
63 // Don't install the code if the bytecode has been flushed or has
64 // already some baseline code installed.
66 return;
67 }
68
69 shared_function_info_->set_baseline_code(*code, kReleaseStore);
70 shared_function_info_->set_age(0);
71 if (v8_flags.trace_baseline) {
72 CodeTracer::Scope scope(isolate->GetCodeTracer());
73 std::stringstream ss;
74 ss << "[Concurrent Sparkplug Off Thread] Function ";
76 ss << " installed\n";
77 OFStream os(scope.file());
78 os << ss.str();
79 }
80 if (IsScript(shared_function_info_->script())) {
82 isolate, LogEventListener::CodeTag::kFunction,
85 Cast<AbstractCode>(code), CodeKind::BASELINE,
87 }
88 }
89
90 private:
95};
96
98 public:
101 int batch_size) {
102 handles_ = isolate->NewPersistentHandles();
103 tasks_.reserve(batch_size);
104 for (int i = 0; i < batch_size; i++) {
105 Tagged<MaybeObject> maybe_sfi = task_queue->get(i);
106 // TODO(victorgomes): Do I need to clear the value?
107 task_queue->set(i, ClearedValue(isolate));
109 // Skip functions where weak reference is no longer valid.
110 if (!maybe_sfi.GetHeapObjectIfWeak(&obj)) continue;
111 // Skip functions where the bytecode has been flushed.
113 if (!CanCompileWithConcurrentBaseline(shared, isolate)) continue;
114 // Skip functions that are already being compiled.
115 if (shared->is_sparkplug_compiling()) continue;
116 tasks_.emplace_back(isolate, handles_.get(), shared);
117 }
118 if (v8_flags.trace_baseline) {
119 CodeTracer::Scope scope(isolate->GetCodeTracer());
120 PrintF(scope.file(), "[Concurrent Sparkplug] compiling %zu functions\n",
121 tasks_.size());
122 }
123 }
124
125 // Executed in the background thread.
126 void Compile(LocalIsolate* local_isolate) {
127 local_isolate->heap()->AttachPersistentHandles(std::move(handles_));
128 for (auto& task : tasks_) {
129 task.Compile(local_isolate);
130 }
131 // Get the handle back since we'd need them to install the code later.
132 handles_ = local_isolate->heap()->DetachPersistentHandles();
133 }
134
135 // Executed in the main thread.
136 void Install(Isolate* isolate) {
137 HandleScope local_scope(isolate);
138 for (auto& task : tasks_) {
139 task.Install(isolate);
140 }
141 }
142
143 private:
144 std::vector<BaselineCompilerTask> tasks_;
145 std::unique_ptr<PersistentHandles> handles_;
146};
147
149 public:
150 class JobDispatcher : public v8::JobTask {
151 public:
153 Isolate* isolate,
154 LockedQueue<std::unique_ptr<BaselineBatchCompilerJob>>* incoming_queue,
155 LockedQueue<std::unique_ptr<BaselineBatchCompilerJob>>* outcoming_queue)
156 : isolate_(isolate),
157 incoming_queue_(incoming_queue),
158 outgoing_queue_(outcoming_queue) {}
159
160 void Run(JobDelegate* delegate) override {
161 base::FlushDenormalsScope flush_denormals_scope(
164 UnparkedScope unparked_scope(&local_isolate);
165 LocalHandleScope handle_scope(&local_isolate);
166
167 while (!incoming_queue_->IsEmpty() && !delegate->ShouldYield()) {
168 std::unique_ptr<BaselineBatchCompilerJob> job;
169 if (!incoming_queue_->Dequeue(&job)) break;
170 DCHECK_NOT_NULL(job);
171 job->Compile(&local_isolate);
172 outgoing_queue_->Enqueue(std::move(job));
173 }
174 isolate_->stack_guard()->RequestInstallBaselineCode();
175 }
176
177 size_t GetMaxConcurrency(size_t worker_count) const override {
178 size_t max_threads = v8_flags.concurrent_sparkplug_max_threads;
179 size_t num_tasks = incoming_queue_->size() + worker_count;
180 if (max_threads > 0) {
181 return std::min(max_threads, num_tasks);
182 }
183 return num_tasks;
184 }
185
186 private:
190 };
191
192 explicit ConcurrentBaselineCompiler(Isolate* isolate) : isolate_(isolate) {
193 if (v8_flags.concurrent_sparkplug) {
194 TaskPriority priority =
195 v8_flags.concurrent_sparkplug_high_priority_threads
196 ? TaskPriority::kUserBlocking
197 : TaskPriority::kUserVisible;
198 job_handle_ = V8::GetCurrentPlatform()->PostJob(
199 priority, std::make_unique<JobDispatcher>(isolate_, &incoming_queue_,
200 &outgoing_queue_));
201 }
202 }
203
205 if (job_handle_ && job_handle_->IsValid()) {
206 // Wait for the job handle to complete, so that we know the queue
207 // pointers are safe.
208 job_handle_->Cancel();
209 }
210 }
211
212 void CompileBatch(Handle<WeakFixedArray> task_queue, int batch_size) {
213 DCHECK(v8_flags.concurrent_sparkplug);
214 RCS_SCOPE(isolate_, RuntimeCallCounterId::kCompileBaseline);
215 incoming_queue_.Enqueue(std::make_unique<BaselineBatchCompilerJob>(
216 isolate_, task_queue, batch_size));
217 job_handle_->NotifyConcurrencyIncrease();
218 }
219
221 while (!outgoing_queue_.IsEmpty()) {
222 std::unique_ptr<BaselineBatchCompilerJob> job;
223 outgoing_queue_.Dequeue(&job);
224 job->Install(isolate_);
225 }
226 }
227
228 private:
230 std::unique_ptr<JobHandle> job_handle_ = nullptr;
233};
234
236 : isolate_(isolate),
237 compilation_queue_(Handle<WeakFixedArray>::null()),
238 last_index_(0),
239 estimated_instruction_size_(0),
240 enabled_(true) {
241 if (v8_flags.concurrent_sparkplug) {
242 concurrent_compiler_ =
243 std::make_unique<ConcurrentBaselineCompiler>(isolate_);
244 }
245}
246
253
255 return v8_flags.concurrent_sparkplug &&
257}
258
261 // Immediately compile the function if batch compilation is disabled.
262 if (!is_enabled()) {
263 IsCompiledScope is_compiled_scope(
264 function->shared()->is_compiled_scope(isolate_));
266 &is_compiled_scope);
267 return;
268 }
269 if (ShouldCompileBatch(*shared)) {
270 if (concurrent()) {
271 CompileBatchConcurrent(*shared);
272 } else {
273 CompileBatch(function);
274 }
275 } else {
276 Enqueue(shared);
277 }
278}
279
281 if (!v8_flags.concurrent_sparkplug || !is_enabled()) return;
282 if (ShouldCompileBatch(shared)) {
284 } else {
286 }
287}
288
293
295 DCHECK(v8_flags.concurrent_sparkplug);
296 concurrent_compiler_->InstallBatch();
297}
298
314
316 {
317 IsCompiledScope is_compiled_scope(
318 function->shared()->is_compiled_scope(isolate_));
320 &is_compiled_scope);
321 }
322 for (int i = 0; i < last_index_; i++) {
323 Tagged<MaybeObject> maybe_sfi = compilation_queue_->get(i);
324 MaybeCompileFunction(maybe_sfi);
326 }
327 ClearBatch();
328}
329
336
339 // Early return if the function is compiled with baseline already or it is not
340 // suitable for baseline compilation.
341 if (shared->HasBaselineCode()) return false;
342 // If we're already compiling this function, return.
343 if (shared->is_sparkplug_compiling()) return false;
344 if (!CanCompileWithBaseline(isolate_, shared)) return false;
345
346 int estimated_size;
347 {
350 shared->GetBytecodeArray(isolate_));
351 }
352 estimated_instruction_size_ += estimated_size;
353 if (v8_flags.trace_baseline_batch_compilation) {
355 PrintF(trace_scope.file(), "[Baseline batch compilation] Enqueued SFI %s",
356 shared->DebugNameCStr().get());
357 PrintF(trace_scope.file(),
358 " with estimated size %d (current budget: %d/%d)\n", estimated_size,
360 v8_flags.baseline_batch_compilation_threshold.value());
361 }
363 v8_flags.baseline_batch_compilation_threshold) {
364 if (v8_flags.trace_baseline_batch_compilation) {
366 PrintF(trace_scope.file(),
367 "[Baseline batch compilation] Compiling current batch of %d "
368 "functions\n",
369 (last_index_ + 1));
370 }
371 return true;
372 }
373 return false;
374}
375
377 Tagged<MaybeObject> maybe_sfi) {
378 Tagged<HeapObject> heapobj;
379 // Skip functions where the weak reference is no longer valid.
380 if (!maybe_sfi.GetHeapObjectIfWeak(&heapobj)) return false;
383 // Skip functions where the bytecode has been flushed.
384 if (!shared->is_compiled()) return false;
385
386 IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate_));
388 isolate_, shared, Compiler::CLEAR_EXCEPTION, &is_compiled_scope);
389}
390
395
396} // namespace baseline
397} // namespace internal
398} // namespace v8
Isolate * isolate_
virtual bool ShouldYield()=0
double InMillisecondsF() const
Definition time.cc:226
static bool CompileSharedWithBaseline(Isolate *isolate, Handle< SharedFunctionInfo > shared, ClearExceptionFlag flag, IsCompiledScope *is_compiled_scope)
Definition compiler.cc:3081
static bool CompileBaseline(Isolate *isolate, DirectHandle< JSFunction > function, ClearExceptionFlag flag, IsCompiledScope *is_compiled_scope)
Definition compiler.cc:3132
static void LogFunctionCompilation(Isolate *isolate, LogEventListener::CodeTag code_type, DirectHandle< Script > script, DirectHandle< SharedFunctionInfo > shared, DirectHandle< FeedbackVector > vector, DirectHandle< AbstractCode > abstract_code, CodeKind kind, double time_taken_ms)
Definition compiler.cc:298
Handle< WeakFixedArray > NewWeakFixedArray(int length, AllocationType allocation=AllocationType::kYoung)
DirectHandle< WeakFixedArray > CopyWeakFixedArrayAndGrow(DirectHandle< WeakFixedArray > array, int grow_by)
Definition factory.cc:2689
static void Destroy(Address *location)
IndirectHandle< Object > Create(Tagged< Object > value)
GlobalHandles * global_handles() const
Definition isolate.h:1416
bool flush_denormals() const
Definition isolate.h:2133
bool EfficiencyModeEnabledForTiering()
Definition isolate.h:2102
StackGuard * stack_guard()
Definition isolate.h:1198
CodeTracer * GetCodeTracer()
Definition isolate.cc:6124
v8::internal::Factory * factory()
Definition isolate.h:1527
std::unique_ptr< PersistentHandles > DetachPersistentHandles()
void AttachPersistentHandles(std::unique_ptr< PersistentHandles > persistent_handles)
bool GetHeapObjectIfWeak(Tagged< HeapObject > *result) const
BaselineBatchCompilerJob(Isolate *isolate, DirectHandle< WeakFixedArray > task_queue, int batch_size)
void Enqueue(DirectHandle< SharedFunctionInfo > shared)
bool ShouldCompileBatch(Tagged< SharedFunctionInfo > shared)
void CompileBatch(DirectHandle< JSFunction > function)
bool MaybeCompileFunction(Tagged< MaybeObject > maybe_sfi)
void CompileBatchConcurrent(Tagged< SharedFunctionInfo > shared)
void EnqueueFunction(DirectHandle< JSFunction > function)
std::unique_ptr< ConcurrentBaselineCompiler > concurrent_compiler_
void EnqueueSFI(Tagged< SharedFunctionInfo > shared)
BaselineCompilerTask(const BaselineCompilerTask &) V8_NOEXCEPT=delete
BaselineCompilerTask(BaselineCompilerTask &&) V8_NOEXCEPT=default
IndirectHandle< SharedFunctionInfo > shared_function_info_
BaselineCompilerTask(Isolate *isolate, PersistentHandles *handles, Tagged< SharedFunctionInfo > sfi)
static int EstimateInstructionSize(Tagged< BytecodeArray > bytecode)
LockedQueue< std::unique_ptr< BaselineBatchCompilerJob > > * incoming_queue_
LockedQueue< std::unique_ptr< BaselineBatchCompilerJob > > * outgoing_queue_
JobDispatcher(Isolate *isolate, LockedQueue< std::unique_ptr< BaselineBatchCompilerJob > > *incoming_queue, LockedQueue< std::unique_ptr< BaselineBatchCompilerJob > > *outcoming_queue)
LockedQueue< std::unique_ptr< BaselineBatchCompilerJob > > outgoing_queue_
LockedQueue< std::unique_ptr< BaselineBatchCompilerJob > > incoming_queue_
void CompileBatch(Handle< WeakFixedArray > task_queue, int batch_size)
Handle< Code > code
SharedFunctionInfoRef shared
static bool CanCompileWithConcurrentBaseline(Tagged< SharedFunctionInfo > shared, Isolate *isolate)
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
void PrintF(const char *format,...)
Definition utils.cc:39
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
void Print(Tagged< Object > obj)
Definition objects.h:774
void ShortPrint(Tagged< Object > obj, FILE *out)
Definition objects.cc:1865
Tagged< MaybeWeak< T > > MakeWeak(Tagged< T > value)
Definition tagged.h:893
Tagged< ClearedWeakValue > ClearedValue(PtrComprCageBase cage_base)
V8_EXPORT_PRIVATE FlagValues v8_flags
bool CanCompileWithBaseline(Isolate *isolate, Tagged< SharedFunctionInfo > shared)
Definition baseline.cc:82
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr ReleaseStoreTag kReleaseStore
Definition globals.h:2910
#define RCS_SCOPE(...)
#define V8_NOEXCEPT
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK(condition)
Definition logging.h:482
bool enabled_
Definition string.cc:1013