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