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/flags.h"
8 #include "src/objects-inl.h"
9 #include "src/tracing/trace-event.h"
10 #include "src/tracing/traced-value.h"
11 #include "src/v8.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(!FLAG_ic_stats)) 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 if (script_name_map_.find(script) != script_name_map_.end()) {
59 return script_name_map_[script].get();
60 }
61 Object* script_name_raw = script->name();
62 if (script_name_raw->IsString()) {
63 String* script_name = String::cast(script_name_raw);
64 char* c_script_name =
65 script_name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)
66 .release();
67 script_name_map_.insert(
68 std::make_pair(script, std::unique_ptr<char[]>(c_script_name)));
69 return c_script_name;
70 } else {
71 script_name_map_.insert(
72 std::make_pair(script, std::unique_ptr<char[]>(nullptr)));
73 return nullptr;
74 }
75 return nullptr;
76 }
77
GetOrCacheFunctionName(JSFunction * function)78 const char* ICStats::GetOrCacheFunctionName(JSFunction* function) {
79 if (function_name_map_.find(function) != function_name_map_.end()) {
80 return function_name_map_[function].get();
81 }
82 SharedFunctionInfo* shared = function->shared();
83 ic_infos_[pos_].is_optimized = function->IsOptimized();
84 char* function_name = shared->DebugName()->ToCString().release();
85 function_name_map_.insert(
86 std::make_pair(function, std::unique_ptr<char[]>(function_name)));
87 return function_name;
88 }
89
ICInfo()90 ICInfo::ICInfo()
91 : function_name(nullptr),
92 script_offset(0),
93 script_name(nullptr),
94 line_num(-1),
95 is_constructor(false),
96 is_optimized(false),
97 map(nullptr),
98 is_dictionary_map(0),
99 number_of_own_descriptors(0) {}
100
Reset()101 void ICInfo::Reset() {
102 type.clear();
103 function_name = nullptr;
104 script_offset = 0;
105 script_name = nullptr;
106 line_num = -1;
107 is_constructor = false;
108 is_optimized = false;
109 state.clear();
110 map = nullptr;
111 is_dictionary_map = false;
112 number_of_own_descriptors = 0;
113 instance_type.clear();
114 }
115
AppendToTracedValue(v8::tracing::TracedValue * value) const116 void ICInfo::AppendToTracedValue(v8::tracing::TracedValue* value) const {
117 value->BeginDictionary();
118 value->SetString("type", type);
119 if (function_name) {
120 value->SetString("functionName", function_name);
121 if (is_optimized) {
122 value->SetInteger("optimized", is_optimized);
123 }
124 }
125 if (script_offset) value->SetInteger("offset", script_offset);
126 if (script_name) value->SetString("scriptName", script_name);
127 if (line_num != -1) value->SetInteger("lineNum", line_num);
128 if (is_constructor) value->SetInteger("constructor", is_constructor);
129 if (!state.empty()) value->SetString("state", state);
130 if (map) {
131 // V8 cannot represent integer above 2^53 - 1 in JavaScript from JSON,
132 // thus `map` should be converted to a string rather than an integer.
133 std::stringstream ss;
134 ss << map;
135 value->SetString("map", ss.str());
136 }
137 if (map) value->SetInteger("dict", is_dictionary_map);
138 if (map) value->SetInteger("own", number_of_own_descriptors);
139 if (!instance_type.empty()) value->SetString("instanceType", instance_type);
140 value->EndDictionary();
141 }
142
143 } // namespace internal
144 } // namespace v8
145