LCOV - code coverage report
Current view: top level - src/debug - debug-coverage.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 84 85 98.8 %
Date: 2017-04-26 Functions: 7 7 100.0 %

          Line data    Source code
       1             : // Copyright 2017 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/debug/debug-coverage.h"
       6             : 
       7             : #include "src/base/hashmap.h"
       8             : #include "src/deoptimizer.h"
       9             : #include "src/frames-inl.h"
      10             : #include "src/isolate.h"
      11             : #include "src/objects-inl.h"
      12             : #include "src/objects.h"
      13             : 
      14             : namespace v8 {
      15             : namespace internal {
      16             : 
      17             : class SharedToCounterMap
      18             :     : public base::TemplateHashMapImpl<SharedFunctionInfo*, uint32_t,
      19             :                                        base::KeyEqualityMatcher<void*>,
      20             :                                        base::DefaultAllocationPolicy> {
      21             :  public:
      22             :   typedef base::TemplateHashMapEntry<SharedFunctionInfo*, uint32_t> Entry;
      23        1028 :   inline void Add(SharedFunctionInfo* key, uint32_t count) {
      24        2056 :     Entry* entry = LookupOrInsert(key, Hash(key), []() { return 0; });
      25        1028 :     uint32_t old_count = entry->value;
      26        1028 :     if (UINT32_MAX - count < old_count) {
      27           0 :       entry->value = UINT32_MAX;
      28             :     } else {
      29        1028 :       entry->value = old_count + count;
      30             :     }
      31        1028 :   }
      32             : 
      33        2937 :   inline uint32_t Get(SharedFunctionInfo* key) {
      34        2937 :     Entry* entry = Lookup(key, Hash(key));
      35        2937 :     if (entry == nullptr) return 0;
      36         840 :     return entry->value;
      37             :   }
      38             : 
      39             :  private:
      40             :   static uint32_t Hash(SharedFunctionInfo* key) {
      41        3965 :     return static_cast<uint32_t>(reinterpret_cast<intptr_t>(key));
      42             :   }
      43             : 
      44             :   DisallowHeapAllocation no_gc;
      45             : };
      46             : 
      47             : namespace {
      48             : int StartPosition(SharedFunctionInfo* info) {
      49             :   int start = info->function_token_position();
      50       26611 :   if (start == kNoSourcePosition) start = info->start_position();
      51             :   return start;
      52             : }
      53             : 
      54       11837 : bool CompareSharedFunctionInfo(SharedFunctionInfo* a, SharedFunctionInfo* b) {
      55             :   int a_start = StartPosition(a);
      56             :   int b_start = StartPosition(b);
      57       11947 :   if (a_start == b_start) return a->end_position() > b->end_position();
      58       11727 :   return a_start < b_start;
      59             : }
      60             : }  // anonymous namespace
      61             : 
      62          80 : Coverage* Coverage::CollectPrecise(Isolate* isolate) {
      63             :   DCHECK(!isolate->is_best_effort_code_coverage());
      64          80 :   Coverage* result = Collect(isolate, isolate->code_coverage_mode());
      65          80 :   if (isolate->is_precise_binary_code_coverage()) {
      66             :     // We do not have to hold onto feedback vectors for invocations we already
      67             :     // reported. So we can reset the list.
      68          36 :     isolate->SetCodeCoverageList(*ArrayList::New(isolate, 0));
      69             :   }
      70          80 :   return result;
      71             : }
      72             : 
      73          78 : Coverage* Coverage::CollectBestEffort(Isolate* isolate) {
      74          78 :   return Collect(isolate, v8::debug::Coverage::kBestEffort);
      75             : }
      76             : 
      77         316 : Coverage* Coverage::Collect(Isolate* isolate,
      78             :                             v8::debug::Coverage::Mode collectionMode) {
      79             :   SharedToCounterMap counter_map;
      80             : 
      81         158 :   switch (isolate->code_coverage_mode()) {
      82             :     case v8::debug::Coverage::kPreciseBinary:
      83             :     case v8::debug::Coverage::kPreciseCount: {
      84             :       bool reset_count = collectionMode != v8::debug::Coverage::kBestEffort;
      85             :       // Feedback vectors are already listed to prevent losing them to GC.
      86             :       DCHECK(isolate->factory()->code_coverage_list()->IsArrayList());
      87             :       Handle<ArrayList> list =
      88             :           Handle<ArrayList>::cast(isolate->factory()->code_coverage_list());
      89         774 :       for (int i = 0; i < list->Length(); i++) {
      90             :         FeedbackVector* vector = FeedbackVector::cast(list->Get(i));
      91             :         SharedFunctionInfo* shared = vector->shared_function_info();
      92             :         DCHECK(shared->IsSubjectToDebugging());
      93         566 :         uint32_t count = static_cast<uint32_t>(vector->invocation_count());
      94         566 :         if (reset_count) vector->clear_invocation_count();
      95         566 :         counter_map.Add(shared, count);
      96             :       }
      97             :       break;
      98             :     }
      99             :     case v8::debug::Coverage::kBestEffort: {
     100             :       DCHECK(!isolate->factory()->code_coverage_list()->IsArrayList());
     101             :       DCHECK_EQ(v8::debug::Coverage::kBestEffort, collectionMode);
     102          54 :       HeapIterator heap_iterator(isolate->heap());
     103      580492 :       while (HeapObject* current_obj = heap_iterator.next()) {
     104      580438 :         if (!current_obj->IsFeedbackVector()) continue;
     105             :         FeedbackVector* vector = FeedbackVector::cast(current_obj);
     106             :         SharedFunctionInfo* shared = vector->shared_function_info();
     107        8118 :         if (!shared->IsSubjectToDebugging()) continue;
     108         462 :         uint32_t count = static_cast<uint32_t>(vector->invocation_count());
     109         462 :         counter_map.Add(shared, count);
     110             :       }
     111          54 :       break;
     112             :     }
     113             :   }
     114             : 
     115             :   // Iterate shared function infos of every script and build a mapping
     116             :   // between source ranges and invocation counts.
     117         158 :   Coverage* result = new Coverage();
     118         158 :   Script::Iterator scripts(isolate);
     119        3505 :   while (Script* script = scripts.Next()) {
     120        6335 :     if (!script->IsUserJavaScript()) continue;
     121             : 
     122             :     // Create and add new script data.
     123             :     Handle<Script> script_handle(script, isolate);
     124         359 :     result->emplace_back(script_handle);
     125        2864 :     std::vector<CoverageFunction>* functions = &result->back().functions;
     126             : 
     127             :     std::vector<SharedFunctionInfo*> sorted;
     128             : 
     129             :     {
     130             :       // Sort functions by start position, from outer to inner functions.
     131         359 :       SharedFunctionInfo::ScriptIterator infos(script_handle);
     132        3296 :       while (SharedFunctionInfo* info = infos.Next()) {
     133        2937 :         sorted.push_back(info);
     134             :       }
     135        3296 :       std::sort(sorted.begin(), sorted.end(), CompareSharedFunctionInfo);
     136             :     }
     137             : 
     138             :     // Stack to track nested functions, referring function by index.
     139             :     std::vector<size_t> nesting;
     140             : 
     141             :     // Use sorted list to reconstruct function nesting.
     142        3655 :     for (SharedFunctionInfo* info : sorted) {
     143        2937 :       int start = StartPosition(info);
     144        2937 :       int end = info->end_position();
     145        2937 :       uint32_t count = counter_map.Get(info);
     146             :       // Find the correct outer function based on start position.
     147       11897 :       while (!nesting.empty() && functions->at(nesting.back()).end <= start) {
     148             :         nesting.pop_back();
     149             :       }
     150        2937 :       if (count != 0) {
     151         752 :         switch (collectionMode) {
     152             :           case v8::debug::Coverage::kPreciseCount:
     153             :             break;
     154             :           case v8::debug::Coverage::kPreciseBinary:
     155          38 :             count = info->has_reported_binary_coverage() ? 0 : 1;
     156          38 :             info->set_has_reported_binary_coverage(true);
     157          38 :             break;
     158             :           case v8::debug::Coverage::kBestEffort:
     159         502 :             count = 1;
     160         502 :             break;
     161             :         }
     162             :       }
     163             :       // Only include a function range if it has a non-0 count, or
     164             :       // if it is directly nested inside a function with non-0 count.
     165        8061 :       if (count != 0 ||
     166        3522 :           (!nesting.empty() && functions->at(nesting.back()).count != 0)) {
     167        2505 :         Handle<String> name(info->DebugName(), isolate);
     168        5010 :         nesting.push_back(functions->size());
     169        2505 :         functions->emplace_back(start, end, count, name);
     170             :       }
     171             :     }
     172             : 
     173             :     // Remove entries for scripts that have no coverage.
     174         359 :     if (functions->empty()) result->pop_back();
     175             :   }
     176         158 :   return result;
     177             : }
     178             : 
     179         196 : void Coverage::SelectMode(Isolate* isolate, debug::Coverage::Mode mode) {
     180         196 :   switch (mode) {
     181             :     case debug::Coverage::kBestEffort:
     182         135 :       isolate->SetCodeCoverageList(isolate->heap()->undefined_value());
     183         135 :       break;
     184             :     case debug::Coverage::kPreciseBinary:
     185             :     case debug::Coverage::kPreciseCount: {
     186          61 :       HandleScope scope(isolate);
     187             :       // Remove all optimized function. Optimized and inlined functions do not
     188             :       // increment invocation count.
     189          61 :       Deoptimizer::DeoptimizeAll(isolate);
     190             :       // Collect existing feedback vectors.
     191             :       std::vector<Handle<FeedbackVector>> vectors;
     192             :       {
     193          61 :         HeapIterator heap_iterator(isolate->heap());
     194      696981 :         while (HeapObject* current_obj = heap_iterator.next()) {
     195      696920 :           if (current_obj->IsSharedFunctionInfo()) {
     196             :             SharedFunctionInfo* shared = SharedFunctionInfo::cast(current_obj);
     197       57713 :             shared->set_has_reported_binary_coverage(false);
     198      639207 :           } else if (current_obj->IsFeedbackVector()) {
     199       10258 :             FeedbackVector* vector = FeedbackVector::cast(current_obj);
     200             :             SharedFunctionInfo* shared = vector->shared_function_info();
     201       20444 :             if (!shared->IsSubjectToDebugging()) continue;
     202          72 :             vectors.emplace_back(vector, isolate);
     203             :           }
     204          61 :         }
     205             :       }
     206             :       // Add collected feedback vectors to the root list lest we lose them to
     207             :       // GC.
     208             :       Handle<ArrayList> list =
     209         122 :           ArrayList::New(isolate, static_cast<int>(vectors.size()));
     210         266 :       for (const auto& vector : vectors) list = ArrayList::Add(list, vector);
     211          61 :       isolate->SetCodeCoverageList(*list);
     212             :       break;
     213             :     }
     214             :   }
     215         196 :   isolate->set_code_coverage_mode(mode);
     216         196 : }
     217             : 
     218             : }  // namespace internal
     219             : }  // namespace v8

Generated by: LCOV version 1.10