| // Copyright 2016 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/ic/ic-stats.h" |
| |
| #include "src/init/v8.h" |
| #include "src/logging/counters.h" |
| #include "src/objects/objects-inl.h" |
| #include "src/tracing/trace-event.h" |
| #include "src/tracing/traced-value.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| base::LazyInstance<ICStats>::type ICStats::instance_ = |
| LAZY_INSTANCE_INITIALIZER; |
| |
| ICStats::ICStats() : ic_infos_(MAX_IC_INFO), pos_(0) { |
| base::Relaxed_Store(&enabled_, 0); |
| } |
| |
| void ICStats::Begin() { |
| if (V8_LIKELY(!TracingFlags::is_ic_stats_enabled())) return; |
| base::Relaxed_Store(&enabled_, 1); |
| } |
| |
| void ICStats::End() { |
| if (base::Relaxed_Load(&enabled_) != 1) return; |
| ++pos_; |
| if (pos_ == MAX_IC_INFO) { |
| Dump(); |
| } |
| base::Relaxed_Store(&enabled_, 0); |
| } |
| |
| void ICStats::Reset() { |
| for (auto ic_info : ic_infos_) { |
| ic_info.Reset(); |
| } |
| pos_ = 0; |
| } |
| |
| void ICStats::Dump() { |
| auto value = v8::tracing::TracedValue::Create(); |
| value->BeginArray("data"); |
| for (int i = 0; i < pos_; ++i) { |
| ic_infos_[i].AppendToTracedValue(value.get()); |
| } |
| value->EndArray(); |
| |
| TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.ic_stats"), "V8.ICStats", |
| TRACE_EVENT_SCOPE_THREAD, "ic-stats", std::move(value)); |
| Reset(); |
| } |
| |
| const char* ICStats::GetOrCacheScriptName(Script script) { |
| Address script_ptr = script.ptr(); |
| if (script_name_map_.find(script_ptr) != script_name_map_.end()) { |
| return script_name_map_[script_ptr].get(); |
| } |
| Object script_name_raw = script.name(); |
| if (script_name_raw.IsString()) { |
| String script_name = String::cast(script_name_raw); |
| char* c_script_name = |
| script_name.ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL) |
| .release(); |
| script_name_map_.insert( |
| std::make_pair(script_ptr, std::unique_ptr<char[]>(c_script_name))); |
| return c_script_name; |
| } else { |
| script_name_map_.insert( |
| std::make_pair(script_ptr, std::unique_ptr<char[]>(nullptr))); |
| return nullptr; |
| } |
| return nullptr; |
| } |
| |
| const char* ICStats::GetOrCacheFunctionName(JSFunction function) { |
| Address function_ptr = function.ptr(); |
| if (function_name_map_.find(function_ptr) != function_name_map_.end()) { |
| return function_name_map_[function_ptr].get(); |
| } |
| SharedFunctionInfo shared = function.shared(); |
| ic_infos_[pos_].is_optimized = function.HasAttachedOptimizedCode(); |
| char* function_name = shared.DebugName().ToCString().release(); |
| function_name_map_.insert( |
| std::make_pair(function_ptr, std::unique_ptr<char[]>(function_name))); |
| return function_name; |
| } |
| |
| ICInfo::ICInfo() |
| : function_name(nullptr), |
| script_offset(0), |
| script_name(nullptr), |
| line_num(-1), |
| column_num(-1), |
| is_constructor(false), |
| is_optimized(false), |
| map(nullptr), |
| is_dictionary_map(false), |
| number_of_own_descriptors(0) {} |
| |
| void ICInfo::Reset() { |
| type.clear(); |
| function_name = nullptr; |
| script_offset = 0; |
| script_name = nullptr; |
| line_num = -1; |
| column_num = -1; |
| is_constructor = false; |
| is_optimized = false; |
| state.clear(); |
| map = nullptr; |
| is_dictionary_map = false; |
| number_of_own_descriptors = 0; |
| instance_type.clear(); |
| } |
| |
| void ICInfo::AppendToTracedValue(v8::tracing::TracedValue* value) const { |
| value->BeginDictionary(); |
| value->SetString("type", type); |
| if (function_name) { |
| value->SetString("functionName", function_name); |
| if (is_optimized) { |
| value->SetInteger("optimized", is_optimized); |
| } |
| } |
| if (script_offset) value->SetInteger("offset", script_offset); |
| if (script_name) value->SetString("scriptName", script_name); |
| if (line_num != -1) value->SetInteger("lineNum", line_num); |
| if (column_num != -1) value->SetInteger("columnNum", column_num); |
| if (is_constructor) value->SetInteger("constructor", is_constructor); |
| if (!state.empty()) value->SetString("state", state); |
| if (map) { |
| // V8 cannot represent integer above 2^53 - 1 in JavaScript from JSON, |
| // thus `map` should be converted to a string rather than an integer. |
| std::stringstream ss; |
| ss << map; |
| value->SetString("map", ss.str()); |
| } |
| if (map) value->SetInteger("dict", is_dictionary_map); |
| if (map) value->SetInteger("own", number_of_own_descriptors); |
| if (!instance_type.empty()) value->SetString("instanceType", instance_type); |
| value->EndDictionary(); |
| } |
| |
| } // namespace internal |
| } // namespace v8 |