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/isolate.h" | 9 #include "src/isolate.h" |
10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
51 } | 51 } |
52 | 52 |
53 bool CompareSharedFunctionInfo(SharedFunctionInfo* a, SharedFunctionInfo* b) { | 53 bool CompareSharedFunctionInfo(SharedFunctionInfo* a, SharedFunctionInfo* b) { |
54 int a_start = StartPosition(a); | 54 int a_start = StartPosition(a); |
55 int b_start = StartPosition(b); | 55 int b_start = StartPosition(b); |
56 if (a_start == b_start) return a->end_position() > b->end_position(); | 56 if (a_start == b_start) return a->end_position() > b->end_position(); |
57 return a_start < b_start; | 57 return a_start < b_start; |
58 } | 58 } |
59 } // anonymous namespace | 59 } // anonymous namespace |
60 | 60 |
61 CoverageScript::CoverageScript(Isolate* isolate, Handle<Script> s, | 61 Coverage* Coverage::Collect(Isolate* isolate, bool reset_count) { |
62 int source_length) | |
63 : script(s), | |
64 toplevel(0, source_length, 1, isolate->factory()->empty_string()) {} | |
65 | |
66 Coverage* Coverage::Collect(Isolate* isolate) { | |
67 SharedToCounterMap counter_map; | 62 SharedToCounterMap counter_map; |
68 | 63 |
69 // Feed invocation count into the counter map. | 64 // Feed invocation count into the counter map. |
70 if (isolate->IsCodeCoverageEnabled()) { | 65 if (isolate->IsCodeCoverageEnabled()) { |
71 // Feedback vectors are already listed to prevent losing them to GC. | 66 // Feedback vectors are already listed to prevent losing them to GC. |
72 Handle<ArrayList> list = | 67 Handle<ArrayList> list = |
73 Handle<ArrayList>::cast(isolate->factory()->code_coverage_list()); | 68 Handle<ArrayList>::cast(isolate->factory()->code_coverage_list()); |
74 for (int i = 0; i < list->Length(); i++) { | 69 for (int i = 0; i < list->Length(); i++) { |
75 FeedbackVector* vector = FeedbackVector::cast(list->Get(i)); | 70 FeedbackVector* vector = FeedbackVector::cast(list->Get(i)); |
76 SharedFunctionInfo* shared = vector->shared_function_info(); | 71 SharedFunctionInfo* shared = vector->shared_function_info(); |
77 DCHECK(shared->IsSubjectToDebugging()); | 72 DCHECK(shared->IsSubjectToDebugging()); |
78 uint32_t count = static_cast<uint32_t>(vector->invocation_count()); | 73 uint32_t count = static_cast<uint32_t>(vector->invocation_count()); |
| 74 if (reset_count) vector->clear_invocation_count(); |
79 counter_map.Add(shared, count); | 75 counter_map.Add(shared, count); |
80 } | 76 } |
81 } else { | 77 } else { |
82 // Iterate the heap to find all feedback vectors and accumulate the | 78 // Iterate the heap to find all feedback vectors and accumulate the |
83 // invocation counts into the map for each shared function info. | 79 // invocation counts into the map for each shared function info. |
84 HeapIterator heap_iterator(isolate->heap()); | 80 HeapIterator heap_iterator(isolate->heap()); |
85 while (HeapObject* current_obj = heap_iterator.next()) { | 81 while (HeapObject* current_obj = heap_iterator.next()) { |
86 if (!current_obj->IsFeedbackVector()) continue; | 82 if (!current_obj->IsFeedbackVector()) continue; |
87 FeedbackVector* vector = FeedbackVector::cast(current_obj); | 83 FeedbackVector* vector = FeedbackVector::cast(current_obj); |
88 SharedFunctionInfo* shared = vector->shared_function_info(); | 84 SharedFunctionInfo* shared = vector->shared_function_info(); |
89 if (!shared->IsSubjectToDebugging()) continue; | 85 if (!shared->IsSubjectToDebugging()) continue; |
90 uint32_t count = static_cast<uint32_t>(vector->invocation_count()); | 86 uint32_t count = static_cast<uint32_t>(vector->invocation_count()); |
| 87 if (reset_count) vector->clear_invocation_count(); |
91 counter_map.Add(shared, count); | 88 counter_map.Add(shared, count); |
92 } | 89 } |
93 } | 90 } |
94 | 91 |
95 // Iterate shared function infos of every script and build a mapping | 92 // Iterate shared function infos of every script and build a mapping |
96 // between source ranges and invocation counts. | 93 // between source ranges and invocation counts. |
97 Coverage* result = new Coverage(); | 94 Coverage* result = new Coverage(); |
98 Script::Iterator scripts(isolate); | 95 Script::Iterator scripts(isolate); |
99 while (Script* script = scripts.Next()) { | 96 while (Script* script = scripts.Next()) { |
100 // Dismiss non-user scripts. | 97 // Dismiss non-user scripts. |
101 if (script->type() != Script::TYPE_NORMAL) continue; | 98 if (script->type() != Script::TYPE_NORMAL) continue; |
102 | 99 |
103 // Create and add new script data. | 100 // Create and add new script data. |
104 int source_end = String::cast(script->source())->length(); | |
105 Handle<Script> script_handle(script, isolate); | 101 Handle<Script> script_handle(script, isolate); |
106 result->emplace_back(isolate, script_handle, source_end); | 102 result->emplace_back(isolate, script_handle); |
| 103 std::vector<CoverageFunction>* functions = &result->back().functions; |
107 | 104 |
108 std::vector<SharedFunctionInfo*> sorted; | 105 std::vector<SharedFunctionInfo*> sorted; |
| 106 bool has_toplevel = false; |
109 | 107 |
110 { | 108 { |
111 // Collect a list of shared function infos sorted by start position. | 109 // Sort functions by start position, from outer to inner functions. |
112 // Shared function infos are usually already sorted. Except for classes. | |
113 // If the start position is the same, sort from outer to inner function. | |
114 SharedFunctionInfo::ScriptIterator infos(script_handle); | 110 SharedFunctionInfo::ScriptIterator infos(script_handle); |
115 while (SharedFunctionInfo* info = infos.Next()) sorted.push_back(info); | 111 while (SharedFunctionInfo* info = infos.Next()) { |
| 112 has_toplevel |= info->is_toplevel(); |
| 113 sorted.push_back(info); |
| 114 } |
116 std::sort(sorted.begin(), sorted.end(), CompareSharedFunctionInfo); | 115 std::sort(sorted.begin(), sorted.end(), CompareSharedFunctionInfo); |
117 } | 116 } |
118 | 117 |
119 std::vector<CoverageRange*> stack; | 118 functions->reserve(sorted.size() + (has_toplevel ? 0 : 1)); |
120 stack.push_back(&result->back().toplevel); | 119 |
| 120 if (!has_toplevel) { |
| 121 // Add a replacement toplevel function if it does not exist. |
| 122 int source_end = String::cast(script->source())->length(); |
| 123 functions->emplace_back(0, source_end, 1u, |
| 124 isolate->factory()->empty_string()); |
| 125 } |
121 | 126 |
122 // Use sorted list to reconstruct function nesting. | 127 // Use sorted list to reconstruct function nesting. |
123 for (SharedFunctionInfo* info : sorted) { | 128 for (SharedFunctionInfo* info : sorted) { |
124 int start = StartPosition(info); | 129 int start = StartPosition(info); |
125 int end = info->end_position(); | 130 int end = info->end_position(); |
126 uint32_t count = counter_map.Get(info); | 131 uint32_t count = counter_map.Get(info); |
127 if (info->is_toplevel()) { | 132 Handle<String> name(info->DebugName(), isolate); |
128 // Top-level function is available. | 133 functions->emplace_back(start, end, count, name); |
129 DCHECK_EQ(1, stack.size()); | |
130 result->back().toplevel.start = start; | |
131 result->back().toplevel.end = end; | |
132 result->back().toplevel.count = count; | |
133 } else { | |
134 // The shared function infos are sorted by start. | |
135 DCHECK_LE(stack.back()->start, start); | |
136 // Drop the stack to the outer function. | |
137 while (start >= stack.back()->end) stack.pop_back(); | |
138 CoverageRange* outer = stack.back(); | |
139 // New nested function. | |
140 DCHECK_LE(end, outer->end); | |
141 Handle<String> name(info->DebugName(), isolate); | |
142 outer->inner.emplace_back(start, end, count, name); | |
143 stack.push_back(&outer->inner.back()); | |
144 } | |
145 } | 134 } |
146 } | 135 } |
147 return result; | 136 return result; |
148 } | 137 } |
149 | 138 |
150 void Coverage::TogglePrecise(Isolate* isolate, bool enable) { | 139 void Coverage::TogglePrecise(Isolate* isolate, bool enable) { |
151 if (enable) { | 140 if (enable) { |
152 HandleScope scope(isolate); | 141 HandleScope scope(isolate); |
153 // Remove all optimized function. Optimized and inlined functions do not | 142 // Remove all optimized function. Optimized and inlined functions do not |
154 // increment invocation count. | 143 // increment invocation count. |
(...skipping 16 matching lines...) Expand all Loading... |
171 ArrayList::New(isolate, static_cast<int>(vectors.size())); | 160 ArrayList::New(isolate, static_cast<int>(vectors.size())); |
172 for (const auto& vector : vectors) list = ArrayList::Add(list, vector); | 161 for (const auto& vector : vectors) list = ArrayList::Add(list, vector); |
173 isolate->SetCodeCoverageList(*list); | 162 isolate->SetCodeCoverageList(*list); |
174 } else { | 163 } else { |
175 isolate->SetCodeCoverageList(isolate->heap()->undefined_value()); | 164 isolate->SetCodeCoverageList(isolate->heap()->undefined_value()); |
176 } | 165 } |
177 } | 166 } |
178 | 167 |
179 } // namespace internal | 168 } // namespace internal |
180 } // namespace v8 | 169 } // namespace v8 |
OLD | NEW |