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 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::NoBarrier_Store(&enabled_, 0); 21} 22 23void ICStats::Begin() { 24 if (V8_LIKELY(!FLAG_ic_stats)) return; 25 base::NoBarrier_Store(&enabled_, 1); 26} 27 28void ICStats::End() { 29 if (base::NoBarrier_Load(&enabled_) != 1) return; 30 ++pos_; 31 if (pos_ == MAX_IC_INFO) { 32 Dump(); 33 } 34 base::NoBarrier_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 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 78const 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 90ICInfo::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 101void 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 116void 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