OLD | NEW |
1 // Copyright 2017 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/debug/debug-coverage.h" | 5 #include "src/debug/debug-coverage.h" |
6 | 6 |
7 #include "src/base/hashmap.h" | 7 #include "src/base/hashmap.h" |
8 #include "src/deoptimizer.h" | 8 #include "src/deoptimizer.h" |
9 #include "src/frames-inl.h" | 9 #include "src/frames-inl.h" |
10 #include "src/isolate.h" | 10 #include "src/isolate.h" |
11 #include "src/objects-inl.h" | |
12 #include "src/objects.h" | 11 #include "src/objects.h" |
| 12 #include "src/objects/debug-objects-inl.h" |
13 | 13 |
14 namespace v8 { | 14 namespace v8 { |
15 namespace internal { | 15 namespace internal { |
16 | 16 |
17 class SharedToCounterMap | 17 class SharedToCounterMap |
18 : public base::TemplateHashMapImpl<SharedFunctionInfo*, uint32_t, | 18 : public base::TemplateHashMapImpl<SharedFunctionInfo*, uint32_t, |
19 base::KeyEqualityMatcher<void*>, | 19 base::KeyEqualityMatcher<void*>, |
20 base::DefaultAllocationPolicy> { | 20 base::DefaultAllocationPolicy> { |
21 public: | 21 public: |
22 typedef base::TemplateHashMapEntry<SharedFunctionInfo*, uint32_t> Entry; | 22 typedef base::TemplateHashMapEntry<SharedFunctionInfo*, uint32_t> Entry; |
(...skipping 27 matching lines...) Expand all Loading... |
50 if (start == kNoSourcePosition) start = info->start_position(); | 50 if (start == kNoSourcePosition) start = info->start_position(); |
51 return start; | 51 return start; |
52 } | 52 } |
53 | 53 |
54 bool CompareSharedFunctionInfo(SharedFunctionInfo* a, SharedFunctionInfo* b) { | 54 bool CompareSharedFunctionInfo(SharedFunctionInfo* a, SharedFunctionInfo* b) { |
55 int a_start = StartPosition(a); | 55 int a_start = StartPosition(a); |
56 int b_start = StartPosition(b); | 56 int b_start = StartPosition(b); |
57 if (a_start == b_start) return a->end_position() > b->end_position(); | 57 if (a_start == b_start) return a->end_position() > b->end_position(); |
58 return a_start < b_start; | 58 return a_start < b_start; |
59 } | 59 } |
| 60 |
| 61 bool CompareCoverageBlock(const CoverageBlock& a, const CoverageBlock& b) { |
| 62 DCHECK(a.start != kNoSourcePosition && a.end != kNoSourcePosition); |
| 63 DCHECK(b.start != kNoSourcePosition && b.end != kNoSourcePosition); |
| 64 if (a.start == b.start) return a.end > b.end; |
| 65 return a.start < b.start; |
| 66 } |
| 67 |
| 68 std::vector<CoverageBlock> GetSortedBlockData(Isolate* isolate, |
| 69 SharedFunctionInfo* shared) { |
| 70 DCHECK(FLAG_block_coverage); |
| 71 DCHECK(shared->HasCoverageInfo()); |
| 72 |
| 73 std::vector<CoverageBlock> result; |
| 74 |
| 75 CoverageInfo* coverage_info = |
| 76 CoverageInfo::cast(shared->GetDebugInfo()->coverage_info()); |
| 77 |
| 78 for (int i = 0; i < coverage_info->SlotCount(); i++) { |
| 79 const int start_pos = coverage_info->StartSourcePosition(i); |
| 80 const int until_pos = coverage_info->EndSourcePosition(i); |
| 81 const int count = coverage_info->BlockCount(i); |
| 82 |
| 83 DCHECK(start_pos != kNoSourcePosition); |
| 84 DCHECK(until_pos != kNoSourcePosition); |
| 85 |
| 86 result.emplace_back(start_pos, until_pos, count); |
| 87 } |
| 88 |
| 89 // Sort according to the block nesting structure. |
| 90 std::sort(result.begin(), result.end(), CompareCoverageBlock); |
| 91 |
| 92 return result; |
| 93 } |
60 } // anonymous namespace | 94 } // anonymous namespace |
61 | 95 |
62 Coverage* Coverage::CollectPrecise(Isolate* isolate) { | 96 Coverage* Coverage::CollectPrecise(Isolate* isolate) { |
63 DCHECK(!isolate->is_best_effort_code_coverage()); | 97 DCHECK(!isolate->is_best_effort_code_coverage()); |
64 Coverage* result = Collect(isolate, isolate->code_coverage_mode()); | 98 Coverage* result = Collect(isolate, isolate->code_coverage_mode()); |
65 if (isolate->is_precise_binary_code_coverage()) { | 99 if (isolate->is_precise_binary_code_coverage()) { |
66 // We do not have to hold onto feedback vectors for invocations we already | 100 // We do not have to hold onto feedback vectors for invocations we already |
67 // reported. So we can reset the list. | 101 // reported. So we can reset the list. |
68 isolate->SetCodeCoverageList(*ArrayList::New(isolate, 0)); | 102 isolate->SetCodeCoverageList(*ArrayList::New(isolate, 0)); |
69 } | 103 } |
70 return result; | 104 return result; |
71 } | 105 } |
72 | 106 |
73 Coverage* Coverage::CollectBestEffort(Isolate* isolate) { | 107 Coverage* Coverage::CollectBestEffort(Isolate* isolate) { |
74 return Collect(isolate, v8::debug::Coverage::kBestEffort); | 108 return Collect(isolate, v8::debug::Coverage::kBestEffort); |
75 } | 109 } |
76 | 110 |
77 Coverage* Coverage::Collect(Isolate* isolate, | 111 Coverage* Coverage::Collect(Isolate* isolate, |
78 v8::debug::Coverage::Mode collectionMode) { | 112 v8::debug::Coverage::Mode collectionMode) { |
79 SharedToCounterMap counter_map; | 113 SharedToCounterMap counter_map; |
80 | 114 |
81 switch (isolate->code_coverage_mode()) { | 115 switch (isolate->code_coverage_mode()) { |
| 116 case v8::debug::Coverage::kBlockCount: |
82 case v8::debug::Coverage::kPreciseBinary: | 117 case v8::debug::Coverage::kPreciseBinary: |
83 case v8::debug::Coverage::kPreciseCount: { | 118 case v8::debug::Coverage::kPreciseCount: { |
84 bool reset_count = collectionMode != v8::debug::Coverage::kBestEffort; | 119 bool reset_count = collectionMode != v8::debug::Coverage::kBestEffort; |
85 // Feedback vectors are already listed to prevent losing them to GC. | 120 // Feedback vectors are already listed to prevent losing them to GC. |
86 DCHECK(isolate->factory()->code_coverage_list()->IsArrayList()); | 121 DCHECK(isolate->factory()->code_coverage_list()->IsArrayList()); |
87 Handle<ArrayList> list = | 122 Handle<ArrayList> list = |
88 Handle<ArrayList>::cast(isolate->factory()->code_coverage_list()); | 123 Handle<ArrayList>::cast(isolate->factory()->code_coverage_list()); |
89 for (int i = 0; i < list->Length(); i++) { | 124 for (int i = 0; i < list->Length(); i++) { |
90 FeedbackVector* vector = FeedbackVector::cast(list->Get(i)); | 125 FeedbackVector* vector = FeedbackVector::cast(list->Get(i)); |
91 SharedFunctionInfo* shared = vector->shared_function_info(); | 126 SharedFunctionInfo* shared = vector->shared_function_info(); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 for (SharedFunctionInfo* info : sorted) { | 177 for (SharedFunctionInfo* info : sorted) { |
143 int start = StartPosition(info); | 178 int start = StartPosition(info); |
144 int end = info->end_position(); | 179 int end = info->end_position(); |
145 uint32_t count = counter_map.Get(info); | 180 uint32_t count = counter_map.Get(info); |
146 // Find the correct outer function based on start position. | 181 // Find the correct outer function based on start position. |
147 while (!nesting.empty() && functions->at(nesting.back()).end <= start) { | 182 while (!nesting.empty() && functions->at(nesting.back()).end <= start) { |
148 nesting.pop_back(); | 183 nesting.pop_back(); |
149 } | 184 } |
150 if (count != 0) { | 185 if (count != 0) { |
151 switch (collectionMode) { | 186 switch (collectionMode) { |
| 187 case v8::debug::Coverage::kBlockCount: |
152 case v8::debug::Coverage::kPreciseCount: | 188 case v8::debug::Coverage::kPreciseCount: |
153 break; | 189 break; |
154 case v8::debug::Coverage::kPreciseBinary: | 190 case v8::debug::Coverage::kPreciseBinary: |
155 count = info->has_reported_binary_coverage() ? 0 : 1; | 191 count = info->has_reported_binary_coverage() ? 0 : 1; |
156 info->set_has_reported_binary_coverage(true); | 192 info->set_has_reported_binary_coverage(true); |
157 break; | 193 break; |
158 case v8::debug::Coverage::kBestEffort: | 194 case v8::debug::Coverage::kBestEffort: |
159 count = 1; | 195 count = 1; |
160 break; | 196 break; |
161 } | 197 } |
162 } | 198 } |
163 // Only include a function range if it has a non-0 count, or | 199 // 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. | 200 // if it is directly nested inside a function with non-0 count. |
165 if (count != 0 || | 201 if (count != 0 || |
166 (!nesting.empty() && functions->at(nesting.back()).count != 0)) { | 202 (!nesting.empty() && functions->at(nesting.back()).count != 0)) { |
167 Handle<String> name(info->DebugName(), isolate); | 203 Handle<String> name(info->DebugName(), isolate); |
168 nesting.push_back(functions->size()); | 204 nesting.push_back(functions->size()); |
169 functions->emplace_back(start, end, count, name); | 205 functions->emplace_back(start, end, count, name); |
| 206 |
| 207 if (FLAG_block_coverage && info->HasCoverageInfo()) { |
| 208 CoverageFunction* function = &functions->back(); |
| 209 function->blocks = GetSortedBlockData(isolate, info); |
| 210 } |
170 } | 211 } |
171 } | 212 } |
172 | 213 |
173 // Remove entries for scripts that have no coverage. | 214 // Remove entries for scripts that have no coverage. |
174 if (functions->empty()) result->pop_back(); | 215 if (functions->empty()) result->pop_back(); |
175 } | 216 } |
176 return result; | 217 return result; |
177 } | 218 } |
178 | 219 |
179 void Coverage::SelectMode(Isolate* isolate, debug::Coverage::Mode mode) { | 220 void Coverage::SelectMode(Isolate* isolate, debug::Coverage::Mode mode) { |
180 switch (mode) { | 221 switch (mode) { |
181 case debug::Coverage::kBestEffort: | 222 case debug::Coverage::kBestEffort: |
| 223 if (FLAG_block_coverage) isolate->debug()->RemoveAllCoverageInfos(); |
182 isolate->SetCodeCoverageList(isolate->heap()->undefined_value()); | 224 isolate->SetCodeCoverageList(isolate->heap()->undefined_value()); |
183 break; | 225 break; |
| 226 case debug::Coverage::kBlockCount: |
184 case debug::Coverage::kPreciseBinary: | 227 case debug::Coverage::kPreciseBinary: |
185 case debug::Coverage::kPreciseCount: { | 228 case debug::Coverage::kPreciseCount: { |
186 HandleScope scope(isolate); | 229 HandleScope scope(isolate); |
187 // Remove all optimized function. Optimized and inlined functions do not | 230 // Remove all optimized function. Optimized and inlined functions do not |
188 // increment invocation count. | 231 // increment invocation count. |
189 Deoptimizer::DeoptimizeAll(isolate); | 232 Deoptimizer::DeoptimizeAll(isolate); |
190 // Collect existing feedback vectors. | 233 // Collect existing feedback vectors. |
191 std::vector<Handle<FeedbackVector>> vectors; | 234 std::vector<Handle<FeedbackVector>> vectors; |
192 { | 235 { |
193 HeapIterator heap_iterator(isolate->heap()); | 236 HeapIterator heap_iterator(isolate->heap()); |
(...skipping 16 matching lines...) Expand all Loading... |
210 for (const auto& vector : vectors) list = ArrayList::Add(list, vector); | 253 for (const auto& vector : vectors) list = ArrayList::Add(list, vector); |
211 isolate->SetCodeCoverageList(*list); | 254 isolate->SetCodeCoverageList(*list); |
212 break; | 255 break; |
213 } | 256 } |
214 } | 257 } |
215 isolate->set_code_coverage_mode(mode); | 258 isolate->set_code_coverage_mode(mode); |
216 } | 259 } |
217 | 260 |
218 } // namespace internal | 261 } // namespace internal |
219 } // namespace v8 | 262 } // namespace v8 |
OLD | NEW |