xref: /third_party/node/deps/v8/src/ic/ic-stats.cc (revision 1cb0ef41)
1// Copyright 2016 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/ic/ic-stats.h"
6
7#include "src/init/v8.h"
8#include "src/logging/counters.h"
9#include "src/objects/objects-inl.h"
10#include "src/tracing/trace-event.h"
11#include "src/tracing/traced-value.h"
12
13namespace v8 {
14namespace internal {
15
16base::LazyInstance<ICStats>::type ICStats::instance_ =
17    LAZY_INSTANCE_INITIALIZER;
18
19ICStats::ICStats() : ic_infos_(MAX_IC_INFO), pos_(0) {
20  base::Relaxed_Store(&enabled_, 0);
21}
22
23void ICStats::Begin() {
24  if (V8_LIKELY(!TracingFlags::is_ic_stats_enabled())) return;
25  base::Relaxed_Store(&enabled_, 1);
26}
27
28void ICStats::End() {
29  if (base::Relaxed_Load(&enabled_) != 1) return;
30  ++pos_;
31  if (pos_ == MAX_IC_INFO) {
32    Dump();
33  }
34  base::Relaxed_Store(&enabled_, 0);
35}
36
37void ICStats::Reset() {
38  for (auto ic_info : ic_infos_) {
39    ic_info.Reset();
40  }
41  pos_ = 0;
42}
43
44void ICStats::Dump() {
45  auto value = v8::tracing::TracedValue::Create();
46  value->BeginArray("data");
47  for (int i = 0; i < pos_; ++i) {
48    ic_infos_[i].AppendToTracedValue(value.get());
49  }
50  value->EndArray();
51
52  TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.ic_stats"), "V8.ICStats",
53                       TRACE_EVENT_SCOPE_THREAD, "ic-stats", std::move(value));
54  Reset();
55}
56
57const char* ICStats::GetOrCacheScriptName(Script script) {
58  Address script_ptr = script.ptr();
59  if (script_name_map_.find(script_ptr) != script_name_map_.end()) {
60    return script_name_map_[script_ptr].get();
61  }
62  Object script_name_raw = script.name();
63  if (script_name_raw.IsString()) {
64    String script_name = String::cast(script_name_raw);
65    char* c_script_name =
66        script_name.ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)
67            .release();
68    script_name_map_.insert(
69        std::make_pair(script_ptr, std::unique_ptr<char[]>(c_script_name)));
70    return c_script_name;
71  }
72  script_name_map_.insert(
73      std::make_pair(script_ptr, std::unique_ptr<char[]>(nullptr)));
74  return nullptr;
75}
76
77const char* ICStats::GetOrCacheFunctionName(JSFunction function) {
78  Address function_ptr = function.ptr();
79  // Lookup the function name or add a null unique_ptr if no entry exists.
80  std::unique_ptr<char[]>& function_name = function_name_map_[function_ptr];
81  if (!function_name) {
82    ic_infos_[pos_].is_optimized = function.HasAttachedOptimizedCode();
83    // Update the map entry with the actual debug name.
84    function_name = function.shared().DebugNameCStr();
85  }
86  return function_name.get();
87}
88
89ICInfo::ICInfo()
90    : function_name(nullptr),
91      script_offset(0),
92      script_name(nullptr),
93      line_num(-1),
94      column_num(-1),
95      is_constructor(false),
96      is_optimized(false),
97      map(nullptr),
98      is_dictionary_map(false),
99      number_of_own_descriptors(0) {}
100
101void ICInfo::Reset() {
102  type.clear();
103  function_name = nullptr;
104  script_offset = 0;
105  script_name = nullptr;
106  line_num = -1;
107  column_num = -1;
108  is_constructor = false;
109  is_optimized = false;
110  state.clear();
111  map = nullptr;
112  is_dictionary_map = false;
113  number_of_own_descriptors = 0;
114  instance_type.clear();
115}
116
117void ICInfo::AppendToTracedValue(v8::tracing::TracedValue* value) const {
118  value->BeginDictionary();
119  value->SetString("type", type);
120  if (function_name) {
121    value->SetString("functionName", function_name);
122    if (is_optimized) {
123      value->SetInteger("optimized", is_optimized);
124    }
125  }
126  if (script_offset) value->SetInteger("offset", script_offset);
127  if (script_name) value->SetString("scriptName", script_name);
128  if (line_num != -1) value->SetInteger("lineNum", line_num);
129  if (column_num != -1) value->SetInteger("columnNum", column_num);
130  if (is_constructor) value->SetInteger("constructor", is_constructor);
131  if (!state.empty()) value->SetString("state", state);
132  if (map) {
133    // V8 cannot represent integer above 2^53 - 1 in JavaScript from JSON,
134    // thus `map` should be converted to a string rather than an integer.
135    std::stringstream ss;
136    ss << map;
137    value->SetString("map", ss.str());
138  }
139  if (map) value->SetInteger("dict", is_dictionary_map);
140  if (map) value->SetInteger("own", number_of_own_descriptors);
141  if (!instance_type.empty()) value->SetString("instanceType", instance_type);
142  value->EndDictionary();
143}
144
145}  // namespace internal
146}  // namespace v8
147