This patch combine three patch which is related to "--gcov" flag.
[platform/framework/web/chromium-efl.git] / gin / v8_platform.cc
1 // Copyright 2014 The Chromium Authors
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 "gin/public/v8_platform.h"
6
7 #include <algorithm>
8
9 #include "base/allocator/partition_allocator/src/partition_alloc/partition_alloc_buildflags.h"
10 #include "base/bit_cast.h"
11 #include "base/check_op.h"
12 #include "base/debug/stack_trace.h"
13 #include "base/functional/bind.h"
14 #include "base/location.h"
15 #include "base/memory/nonscannable_memory.h"
16 #include "base/memory/raw_ptr.h"
17 #include "base/no_destructor.h"
18 #include "base/system/sys_info.h"
19 #include "base/task/post_job.h"
20 #include "base/task/task_traits.h"
21 #include "base/task/thread_pool.h"
22 #include "base/task/thread_pool/thread_pool_instance.h"
23 #include "base/threading/scoped_blocking_call.h"
24 #include "base/threading/scoped_blocking_call_internal.h"
25 #include "base/trace_event/trace_event.h"
26 #include "base/tracing_buildflags.h"
27 #include "build/build_config.h"
28 #include "gin/per_isolate_data.h"
29 #include "gin/thread_isolation.h"
30 #include "gin/v8_platform_thread_isolated_allocator.h"
31 #include "v8_platform_page_allocator.h"
32
33 namespace gin {
34
35 namespace {
36
37 base::LazyInstance<V8Platform>::Leaky g_v8_platform = LAZY_INSTANCE_INITIALIZER;
38
39 void PrintStackTrace() {
40   base::debug::StackTrace trace;
41   trace.Print();
42 }
43
44 class ConvertableToTraceFormatWrapper final
45     : public base::trace_event::ConvertableToTraceFormat {
46  public:
47   explicit ConvertableToTraceFormatWrapper(
48       std::unique_ptr<v8::ConvertableToTraceFormat> inner)
49       : inner_(std::move(inner)) {}
50   ConvertableToTraceFormatWrapper(const ConvertableToTraceFormatWrapper&) =
51       delete;
52   ConvertableToTraceFormatWrapper& operator=(
53       const ConvertableToTraceFormatWrapper&) = delete;
54   ~ConvertableToTraceFormatWrapper() override = default;
55   void AppendAsTraceFormat(std::string* out) const final {
56     inner_->AppendAsTraceFormat(out);
57   }
58
59  private:
60   std::unique_ptr<v8::ConvertableToTraceFormat> inner_;
61 };
62
63 #if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
64 class EnabledStateObserverImpl final
65     : public base::trace_event::TraceLog::EnabledStateObserver {
66  public:
67   EnabledStateObserverImpl() {
68     base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
69   }
70
71   EnabledStateObserverImpl(const EnabledStateObserverImpl&) = delete;
72
73   EnabledStateObserverImpl& operator=(const EnabledStateObserverImpl&) = delete;
74
75   ~EnabledStateObserverImpl() override {
76     base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(
77         this);
78   }
79
80   void OnTraceLogEnabled() final {
81     base::AutoLock lock(mutex_);
82     for (auto* o : observers_) {
83       o->OnTraceEnabled();
84     }
85   }
86
87   void OnTraceLogDisabled() final {
88     base::AutoLock lock(mutex_);
89     for (auto* o : observers_) {
90       o->OnTraceDisabled();
91     }
92   }
93
94   void AddObserver(v8::TracingController::TraceStateObserver* observer) {
95     {
96       base::AutoLock lock(mutex_);
97       DCHECK(!observers_.count(observer));
98       observers_.insert(observer);
99     }
100
101     // Fire the observer if recording is already in progress.
102     if (base::trace_event::TraceLog::GetInstance()->IsEnabled())
103       observer->OnTraceEnabled();
104   }
105
106   void RemoveObserver(v8::TracingController::TraceStateObserver* observer) {
107     base::AutoLock lock(mutex_);
108     DCHECK(observers_.count(observer) == 1);
109     observers_.erase(observer);
110   }
111
112  private:
113   base::Lock mutex_;
114   std::unordered_set<v8::TracingController::TraceStateObserver*> observers_;
115 };
116
117 base::LazyInstance<EnabledStateObserverImpl>::Leaky g_trace_state_dispatcher =
118     LAZY_INSTANCE_INITIALIZER;
119 #endif  // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
120
121 #if BUILDFLAG(USE_PARTITION_ALLOC)
122
123 base::LazyInstance<gin::PageAllocator>::Leaky g_page_allocator =
124     LAZY_INSTANCE_INITIALIZER;
125
126 #endif  // BUILDFLAG(USE_PARTITION_ALLOC)
127
128 base::TaskPriority ToBaseTaskPriority(v8::TaskPriority priority) {
129   switch (priority) {
130     case v8::TaskPriority::kBestEffort:
131       return base::TaskPriority::BEST_EFFORT;
132     case v8::TaskPriority::kUserVisible:
133       return base::TaskPriority::USER_VISIBLE;
134     case v8::TaskPriority::kUserBlocking:
135       return base::TaskPriority::USER_BLOCKING;
136   }
137 }
138
139 base::Location ToBaseLocation(const v8::SourceLocation& location) {
140   return base::Location::Current(location.Function(), location.FileName(),
141                                  location.Line());
142 }
143
144 class JobDelegateImpl : public v8::JobDelegate {
145  public:
146   explicit JobDelegateImpl(base::JobDelegate* delegate) : delegate_(delegate) {}
147   JobDelegateImpl() = default;
148
149   JobDelegateImpl(const JobDelegateImpl&) = delete;
150   JobDelegateImpl& operator=(const JobDelegateImpl&) = delete;
151
152   // v8::JobDelegate:
153   bool ShouldYield() override { return delegate_->ShouldYield(); }
154   void NotifyConcurrencyIncrease() override {
155     delegate_->NotifyConcurrencyIncrease();
156   }
157   uint8_t GetTaskId() override { return delegate_->GetTaskId(); }
158   bool IsJoiningThread() const override { return delegate_->IsJoiningThread(); }
159
160  private:
161   raw_ptr<base::JobDelegate> delegate_;
162 };
163
164 class JobHandleImpl : public v8::JobHandle {
165  public:
166   explicit JobHandleImpl(base::JobHandle handle) : handle_(std::move(handle)) {}
167   ~JobHandleImpl() override = default;
168
169   JobHandleImpl(const JobHandleImpl&) = delete;
170   JobHandleImpl& operator=(const JobHandleImpl&) = delete;
171
172   // v8::JobHandle:
173   void NotifyConcurrencyIncrease() override {
174     handle_.NotifyConcurrencyIncrease();
175   }
176   bool UpdatePriorityEnabled() const override { return true; }
177   void UpdatePriority(v8::TaskPriority new_priority) override {
178     handle_.UpdatePriority(ToBaseTaskPriority(new_priority));
179   }
180   void Join() override { handle_.Join(); }
181   void Cancel() override { handle_.Cancel(); }
182   void CancelAndDetach() override { handle_.CancelAndDetach(); }
183   bool IsActive() override { return handle_.IsActive(); }
184   bool IsValid() override { return !!handle_; }
185
186  private:
187   base::JobHandle handle_;
188 };
189
190 class ScopedBlockingCallImpl : public v8::ScopedBlockingCall {
191  public:
192   explicit ScopedBlockingCallImpl(v8::BlockingType blocking_type)
193       : scoped_blocking_call_(ToBaseBlockingType(blocking_type),
194                               base::internal::UncheckedScopedBlockingCall::
195                                   BlockingCallType::kRegular) {}
196   ~ScopedBlockingCallImpl() override = default;
197
198   ScopedBlockingCallImpl(const ScopedBlockingCallImpl&) = delete;
199   ScopedBlockingCallImpl& operator=(const ScopedBlockingCallImpl&) = delete;
200
201  private:
202   static base::BlockingType ToBaseBlockingType(v8::BlockingType type) {
203     switch (type) {
204       case v8::BlockingType::kMayBlock:
205         return base::BlockingType::MAY_BLOCK;
206       case v8::BlockingType::kWillBlock:
207         return base::BlockingType::WILL_BLOCK;
208     }
209   }
210
211   base::internal::UncheckedScopedBlockingCall scoped_blocking_call_;
212 };
213
214 }  // namespace
215
216 }  // namespace gin
217
218 namespace base {
219 namespace trace_event {
220
221 // Allow std::unique_ptr<v8::ConvertableToTraceFormat> to be a valid
222 // initialization value for trace macros.
223 template <>
224 struct base::trace_event::TraceValue::Helper<
225     std::unique_ptr<v8::ConvertableToTraceFormat>> {
226   static constexpr unsigned char kType = TRACE_VALUE_TYPE_CONVERTABLE;
227   static inline void SetValue(
228       TraceValue* v,
229       std::unique_ptr<v8::ConvertableToTraceFormat> value) {
230     // NOTE: |as_convertable| is an owning pointer, so using new here
231     // is acceptable.
232     v->as_convertable =
233         new gin::ConvertableToTraceFormatWrapper(std::move(value));
234   }
235 };
236
237 }  // namespace trace_event
238 }  // namespace base
239
240 namespace gin {
241
242 class V8Platform::TracingControllerImpl : public v8::TracingController {
243  public:
244   TracingControllerImpl() = default;
245   TracingControllerImpl(const TracingControllerImpl&) = delete;
246   TracingControllerImpl& operator=(const TracingControllerImpl&) = delete;
247   ~TracingControllerImpl() override = default;
248
249   // TracingController implementation.
250 #if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
251   const uint8_t* GetCategoryGroupEnabled(const char* name) override {
252     return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
253   }
254   uint64_t AddTraceEvent(
255       char phase,
256       const uint8_t* category_enabled_flag,
257       const char* name,
258       const char* scope,
259       uint64_t id,
260       uint64_t bind_id,
261       int32_t num_args,
262       const char** arg_names,
263       const uint8_t* arg_types,
264       const uint64_t* arg_values,
265       std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
266       unsigned int flags) override {
267     base::trace_event::TraceArguments args(
268         num_args, arg_names, arg_types,
269         reinterpret_cast<const unsigned long long*>(arg_values),
270         arg_convertables);
271     DCHECK_LE(num_args, 2);
272     base::trace_event::TraceEventHandle handle =
273         TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_BIND_ID(
274             phase, category_enabled_flag, name, scope, id, bind_id, &args,
275             flags);
276     uint64_t result;
277     memcpy(&result, &handle, sizeof(result));
278     return result;
279   }
280   uint64_t AddTraceEventWithTimestamp(
281       char phase,
282       const uint8_t* category_enabled_flag,
283       const char* name,
284       const char* scope,
285       uint64_t id,
286       uint64_t bind_id,
287       int32_t num_args,
288       const char** arg_names,
289       const uint8_t* arg_types,
290       const uint64_t* arg_values,
291       std::unique_ptr<v8::ConvertableToTraceFormat>* arg_convertables,
292       unsigned int flags,
293       int64_t timestampMicroseconds) override {
294     base::trace_event::TraceArguments args(
295         num_args, arg_names, arg_types,
296         reinterpret_cast<const unsigned long long*>(arg_values),
297         arg_convertables);
298     DCHECK_LE(num_args, 2);
299     base::TimeTicks timestamp =
300         base::TimeTicks() + base::Microseconds(timestampMicroseconds);
301     base::trace_event::TraceEventHandle handle =
302         TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_THREAD_ID_AND_TIMESTAMP(
303             phase, category_enabled_flag, name, scope, id, bind_id,
304             TRACE_EVENT_API_CURRENT_THREAD_ID, timestamp, &args, flags);
305     uint64_t result;
306     memcpy(&result, &handle, sizeof(result));
307     return result;
308   }
309   void UpdateTraceEventDuration(const uint8_t* category_enabled_flag,
310                                 const char* name,
311                                 uint64_t handle) override {
312     base::trace_event::TraceEventHandle traceEventHandle;
313     memcpy(&traceEventHandle, &handle, sizeof(handle));
314     TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_enabled_flag, name,
315                                                 traceEventHandle);
316   }
317   void AddTraceStateObserver(TraceStateObserver* observer) override {
318     g_trace_state_dispatcher.Get().AddObserver(observer);
319   }
320   void RemoveTraceStateObserver(TraceStateObserver* observer) override {
321     g_trace_state_dispatcher.Get().RemoveObserver(observer);
322   }
323 #endif  // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
324 };
325
326 // static
327 V8Platform* V8Platform::Get() { return g_v8_platform.Pointer(); }
328
329 V8Platform::V8Platform() : tracing_controller_(new TracingControllerImpl) {}
330
331 V8Platform::~V8Platform() = default;
332
333 #if BUILDFLAG(USE_PARTITION_ALLOC)
334 PageAllocator* V8Platform::GetPageAllocator() {
335   return g_page_allocator.Pointer();
336 }
337
338 #if defined(ENABLE_WRT_JS)
339 v8::PageAllocator* V8Platform::GetCurrentPageAllocator() {
340   return g_page_allocator.Pointer();
341 }
342 #endif
343
344 #if BUILDFLAG(ENABLE_THREAD_ISOLATION)
345 ThreadIsolatedAllocator* V8Platform::GetThreadIsolatedAllocator() {
346   if (!GetThreadIsolationData().Initialized()) {
347     return nullptr;
348   }
349   return GetThreadIsolationData().allocator.get();
350 }
351 #endif  // BUILDFLAG(ENABLE_THREAD_ISOLATION)
352
353 void V8Platform::OnCriticalMemoryPressure() {
354 // We only have a reservation on 32-bit Windows systems.
355 // TODO(bbudge) Make the #if's in BlinkInitializer match.
356 #if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_32_BITS)
357   partition_alloc::ReleaseReservation();
358 #endif
359 }
360
361 v8::ZoneBackingAllocator* V8Platform::GetZoneBackingAllocator() {
362   static struct Allocator final : v8::ZoneBackingAllocator {
363     MallocFn GetMallocFn() const override {
364       return &base::AllocNonQuarantinable;
365     }
366     FreeFn GetFreeFn() const override { return &base::FreeNonQuarantinable; }
367   } allocator;
368   return &allocator;
369 }
370 #endif  // BUILDFLAG(USE_PARTITION_ALLOC)
371
372 std::shared_ptr<v8::TaskRunner> V8Platform::GetForegroundTaskRunner(
373     v8::Isolate* isolate,
374     v8::TaskPriority priority) {
375   PerIsolateData* data = PerIsolateData::From(isolate);
376   if (!data->low_priority_task_runner()) {
377     return data->task_runner();
378   }
379
380   switch (priority) {
381     case v8::TaskPriority::kUserBlocking:
382       // blink::scheduler::TaskPriority::kDefaultPriority
383       return data->task_runner();
384     case v8::TaskPriority::kUserVisible:
385     case v8::TaskPriority::kBestEffort:
386       // blink::scheduler::TaskPriority::kLowPriority
387       return data->low_priority_task_runner();
388     default:
389       NOTREACHED() << "Unsupported TaskPriority.";
390       return data->task_runner();
391   }
392 }
393
394 int V8Platform::NumberOfWorkerThreads() {
395   // V8Platform assumes the number of workers used by the scheduler for user
396   // blocking tasks is an upper bound.
397   const size_t num_foreground_workers =
398       base::ThreadPoolInstance::Get()
399           ->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
400               {base::TaskPriority::USER_BLOCKING});
401   DCHECK_GE(num_foreground_workers,
402             base::ThreadPoolInstance::Get()
403                 ->GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
404                     {base::TaskPriority::USER_VISIBLE}));
405   return std::max(1, static_cast<int>(num_foreground_workers));
406 }
407
408 void V8Platform::PostTaskOnWorkerThreadImpl(
409     v8::TaskPriority priority,
410     std::unique_ptr<v8::Task> task,
411     const v8::SourceLocation& location) {
412   base::ThreadPool::PostTask(ToBaseLocation(location),
413                              {ToBaseTaskPriority(priority)},
414                              base::BindOnce(&v8::Task::Run, std::move(task)));
415 }
416
417 void V8Platform::PostDelayedTaskOnWorkerThreadImpl(
418     v8::TaskPriority priority,
419     std::unique_ptr<v8::Task> task,
420     double delay_in_seconds,
421     const v8::SourceLocation& location) {
422   base::ThreadPool::PostDelayedTask(
423       ToBaseLocation(location), {ToBaseTaskPriority(priority)},
424       base::BindOnce(&v8::Task::Run, std::move(task)),
425       base::Seconds(delay_in_seconds));
426 }
427
428 std::unique_ptr<v8::JobHandle> V8Platform::CreateJobImpl(
429     v8::TaskPriority priority,
430     std::unique_ptr<v8::JobTask> job_task,
431     const v8::SourceLocation& location) {
432   // Ownership of |job_task| is assumed by |worker_task|, while
433   // |max_concurrency_callback| uses an unretained pointer.
434   auto* job_task_ptr = job_task.get();
435   auto handle =
436       base::CreateJob(ToBaseLocation(location), {ToBaseTaskPriority(priority)},
437                       base::BindRepeating(
438                           [](const std::unique_ptr<v8::JobTask>& job_task,
439                              base::JobDelegate* delegate) {
440                             JobDelegateImpl delegate_impl(delegate);
441                             job_task->Run(&delegate_impl);
442                           },
443                           std::move(job_task)),
444                       base::BindRepeating(
445                           [](v8::JobTask* job_task, size_t worker_count) {
446                             return job_task->GetMaxConcurrency(worker_count);
447                           },
448                           base::Unretained(job_task_ptr)));
449
450   return std::make_unique<JobHandleImpl>(std::move(handle));
451 }
452
453 std::unique_ptr<v8::ScopedBlockingCall> V8Platform::CreateBlockingScope(
454     v8::BlockingType blocking_type) {
455   return std::make_unique<ScopedBlockingCallImpl>(blocking_type);
456 }
457
458 bool V8Platform::IdleTasksEnabled(v8::Isolate* isolate) {
459   return PerIsolateData::From(isolate)->task_runner()->IdleTasksEnabled();
460 }
461
462 double V8Platform::MonotonicallyIncreasingTime() {
463   return base::TimeTicks::Now().ToInternalValue() /
464       static_cast<double>(base::Time::kMicrosecondsPerSecond);
465 }
466
467 double V8Platform::CurrentClockTimeMillis() {
468   return static_cast<double>(time_clamper_.ClampToMillis(base::Time::Now()));
469 }
470
471 int64_t V8Platform::CurrentClockTimeMilliseconds() {
472   return time_clamper_.ClampToMillis(base::Time::Now());
473 }
474
475 double V8Platform::CurrentClockTimeMillisecondsHighResolution() {
476   return time_clamper_.ClampToMillisHighResolution(base::Time::Now());
477 }
478
479 v8::TracingController* V8Platform::GetTracingController() {
480   return tracing_controller_.get();
481 }
482
483 v8::Platform::StackTracePrinter V8Platform::GetStackTracePrinter() {
484   return PrintStackTrace;
485 }
486
487 }  // namespace gin