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 
13 namespace v8 {
14 namespace internal {
15 
16 base::LazyInstance<ICStats>::type ICStats::instance_ =
17     LAZY_INSTANCE_INITIALIZER;
18 
ICStats()19 ICStats::ICStats() : ic_infos_(MAX_IC_INFO), pos_(0) {
20   base::Relaxed_Store(&enabled_, 0);
21 }
22 
Begin()23 void ICStats::Begin() {
24   if (V8_LIKELY(!TracingFlags::is_ic_stats_enabled())) return;
25   base::Relaxed_Store(&enabled_, 1);
26 }
27 
End()28 void 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 
Reset()37 void ICStats::Reset() {
38   for (auto ic_info : ic_infos_) {
39     ic_info.Reset();
40   }
41   pos_ = 0;
42 }
43 
Dump()44 void 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 
GetOrCacheScriptName(Script script)57 const 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   } else {
72     script_name_map_.insert(
73         std::make_pair(script_ptr, std::unique_ptr<char[]>(nullptr)));
74     return nullptr;
75   }
76   return nullptr;
77 }
78 
GetOrCacheFunctionName(JSFunction function)79 const char* ICStats::GetOrCacheFunctionName(JSFunction function) {
80   Address function_ptr = function.ptr();
81   if (function_name_map_.find(function_ptr) != function_name_map_.end()) {
82     return function_name_map_[function_ptr].get();
83   }
84   SharedFunctionInfo shared = function.shared();
85   ic_infos_[pos_].is_optimized = function.HasAttachedOptimizedCode();
86   char* function_name = shared.DebugName().ToCString().release();
87   function_name_map_.insert(
88       std::make_pair(function_ptr, std::unique_ptr<char[]>(function_name)));
89   return function_name;
90 }
91 
ICInfo()92 ICInfo::ICInfo()
93     : function_name(nullptr),
94       script_offset(0),
95       script_name(nullptr),
96       line_num(-1),
97       column_num(-1),
98       is_constructor(false),
99       is_optimized(false),
100       map(nullptr),
101       is_dictionary_map(false),
102       number_of_own_descriptors(0) {}
103 
Reset()104 void ICInfo::Reset() {
105   type.clear();
106   function_name = nullptr;
107   script_offset = 0;
108   script_name = nullptr;
109   line_num = -1;
110   column_num = -1;
111   is_constructor = false;
112   is_optimized = false;
113   state.clear();
114   map = nullptr;
115   is_dictionary_map = false;
116   number_of_own_descriptors = 0;
117   instance_type.clear();
118 }
119 
AppendToTracedValue(v8::tracing::TracedValue * value) const120 void ICInfo::AppendToTracedValue(v8::tracing::TracedValue* value) const {
121   value->BeginDictionary();
122   value->SetString("type", type);
123   if (function_name) {
124     value->SetString("functionName", function_name);
125     if (is_optimized) {
126       value->SetInteger("optimized", is_optimized);
127     }
128   }
129   if (script_offset) value->SetInteger("offset", script_offset);
130   if (script_name) value->SetString("scriptName", script_name);
131   if (line_num != -1) value->SetInteger("lineNum", line_num);
132   if (column_num != -1) value->SetInteger("columnNum", column_num);
133   if (is_constructor) value->SetInteger("constructor", is_constructor);
134   if (!state.empty()) value->SetString("state", state);
135   if (map) {
136     // V8 cannot represent integer above 2^53 - 1 in JavaScript from JSON,
137     // thus `map` should be converted to a string rather than an integer.
138     std::stringstream ss;
139     ss << map;
140     value->SetString("map", ss.str());
141   }
142   if (map) value->SetInteger("dict", is_dictionary_map);
143   if (map) value->SetInteger("own", number_of_own_descriptors);
144   if (!instance_type.empty()) value->SetString("instanceType", instance_type);
145   value->EndDictionary();
146 }
147 
148 }  // namespace internal
149 }  // namespace v8
150