Home | History | Annotate | Download | only in ic
      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 
     19 ICStats::ICStats() : ic_infos_(MAX_IC_INFO), pos_(0) {
     20   base::NoBarrier_Store(&enabled_, 0);
     21 }
     22 
     23 void ICStats::Begin() {
     24   if (V8_LIKELY(!FLAG_ic_stats)) return;
     25   base::NoBarrier_Store(&enabled_, 1);
     26 }
     27 
     28 void 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 
     37 void ICStats::Reset() {
     38   for (auto ic_info : ic_infos_) {
     39     ic_info.Reset();
     40   }
     41   pos_ = 0;
     42 }
     43 
     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 
     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 
     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 
     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 
    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 
    116 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