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 25 matching lines...) Expand all Loading... |
36 } | 36 } |
37 | 37 |
38 private: | 38 private: |
39 static uint32_t Hash(SharedFunctionInfo* key) { | 39 static uint32_t Hash(SharedFunctionInfo* key) { |
40 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(key)); | 40 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(key)); |
41 } | 41 } |
42 | 42 |
43 DisallowHeapAllocation no_gc; | 43 DisallowHeapAllocation no_gc; |
44 }; | 44 }; |
45 | 45 |
| 46 namespace { |
| 47 int StartPosition(SharedFunctionInfo* info) { |
| 48 int start = info->function_token_position(); |
| 49 if (start == kNoSourcePosition) start = info->start_position(); |
| 50 return start; |
| 51 } |
| 52 |
| 53 bool CompareSharedFunctionInfo(SharedFunctionInfo* a, SharedFunctionInfo* b) { |
| 54 int a_start = StartPosition(a); |
| 55 int b_start = StartPosition(b); |
| 56 if (a_start == b_start) return a->end_position() > b->end_position(); |
| 57 return a_start < b_start; |
| 58 } |
| 59 } // anonymous namespace |
| 60 |
46 std::vector<Coverage::ScriptData> Coverage::Collect(Isolate* isolate) { | 61 std::vector<Coverage::ScriptData> Coverage::Collect(Isolate* isolate) { |
47 SharedToCounterMap counter_map; | 62 SharedToCounterMap counter_map; |
48 | 63 |
| 64 // Feed invocation count into the counter map. |
49 if (isolate->IsCodeCoverageEnabled()) { | 65 if (isolate->IsCodeCoverageEnabled()) { |
50 // Feedback vectors are already listed to prevent losing them to GC. | 66 // Feedback vectors are already listed to prevent losing them to GC. |
51 Handle<ArrayList> list = | 67 Handle<ArrayList> list = |
52 Handle<ArrayList>::cast(isolate->factory()->code_coverage_list()); | 68 Handle<ArrayList>::cast(isolate->factory()->code_coverage_list()); |
53 for (int i = 0; i < list->Length(); i++) { | 69 for (int i = 0; i < list->Length(); i++) { |
54 FeedbackVector* vector = FeedbackVector::cast(list->Get(i)); | 70 FeedbackVector* vector = FeedbackVector::cast(list->Get(i)); |
55 SharedFunctionInfo* shared = vector->shared_function_info(); | 71 SharedFunctionInfo* shared = vector->shared_function_info(); |
56 DCHECK(shared->IsSubjectToDebugging()); | 72 DCHECK(shared->IsSubjectToDebugging()); |
57 uint32_t count = static_cast<uint32_t>(vector->invocation_count()); | 73 uint32_t count = static_cast<uint32_t>(vector->invocation_count()); |
58 counter_map.Add(shared, count); | 74 counter_map.Add(shared, count); |
59 } | 75 } |
60 } else { | 76 } else { |
61 // Iterate the heap to find all feedback vectors and accumulate the | 77 // Iterate the heap to find all feedback vectors and accumulate the |
62 // invocation counts into the map for each shared function info. | 78 // invocation counts into the map for each shared function info. |
63 HeapIterator heap_iterator(isolate->heap()); | 79 HeapIterator heap_iterator(isolate->heap()); |
64 // Initializing the heap iterator might have triggered a GC, which | |
65 // invalidates entries in the counter_map. | |
66 DCHECK_EQ(0, counter_map.occupancy()); | |
67 while (HeapObject* current_obj = heap_iterator.next()) { | 80 while (HeapObject* current_obj = heap_iterator.next()) { |
68 if (!current_obj->IsFeedbackVector()) continue; | 81 if (!current_obj->IsFeedbackVector()) continue; |
69 FeedbackVector* vector = FeedbackVector::cast(current_obj); | 82 FeedbackVector* vector = FeedbackVector::cast(current_obj); |
70 SharedFunctionInfo* shared = vector->shared_function_info(); | 83 SharedFunctionInfo* shared = vector->shared_function_info(); |
71 if (!shared->IsSubjectToDebugging()) continue; | 84 if (!shared->IsSubjectToDebugging()) continue; |
72 uint32_t count = static_cast<uint32_t>(vector->invocation_count()); | 85 uint32_t count = static_cast<uint32_t>(vector->invocation_count()); |
73 counter_map.Add(shared, count); | 86 counter_map.Add(shared, count); |
74 } | 87 } |
75 } | 88 } |
76 | 89 |
77 // Make sure entries in the counter map is not invalidated by GC. | |
78 DisallowHeapAllocation no_gc; | |
79 | |
80 std::vector<Range*> stack; | |
81 | |
82 // Iterate shared function infos of every script and build a mapping | 90 // Iterate shared function infos of every script and build a mapping |
83 // between source ranges and invocation counts. | 91 // between source ranges and invocation counts. |
84 std::vector<Coverage::ScriptData> result; | 92 std::vector<Coverage::ScriptData> result; |
85 Script::Iterator scripts(isolate); | 93 Script::Iterator scripts(isolate); |
86 while (Script* script = scripts.Next()) { | 94 while (Script* script = scripts.Next()) { |
87 // Dismiss non-user scripts. | 95 // Dismiss non-user scripts. |
88 if (script->type() != Script::TYPE_NORMAL) continue; | 96 if (script->type() != Script::TYPE_NORMAL) continue; |
89 DCHECK(stack.empty()); | 97 |
| 98 // Create and add new script data. |
90 int source_length = String::cast(script->source())->length(); | 99 int source_length = String::cast(script->source())->length(); |
91 result.emplace_back(Handle<Script>(script, isolate), source_length); | 100 result.emplace_back(Handle<Script>(script, isolate), source_length); |
| 101 |
| 102 std::vector<SharedFunctionInfo*> sorted; |
| 103 |
| 104 { |
| 105 // Collect a list of shared function infos sorted by start position. |
| 106 // Shared function infos are usually already sorted. Except for classes. |
| 107 // If the start position is the same, sort from outer to inner function. |
| 108 HandleScope scope(isolate); |
| 109 SharedFunctionInfo::ScriptIterator infos(Handle<Script>(script, isolate)); |
| 110 while (SharedFunctionInfo* info = infos.Next()) sorted.push_back(info); |
| 111 std::sort(sorted.begin(), sorted.end(), CompareSharedFunctionInfo); |
| 112 } |
| 113 |
| 114 std::vector<Range*> stack; |
92 stack.push_back(&result.back().toplevel); | 115 stack.push_back(&result.back().toplevel); |
93 // Iterate through the list of shared function infos, reconstruct the | 116 |
94 // nesting, and compute the ranges covering different invocation counts. | 117 // Use sorted list to reconstruct function nesting. |
95 HandleScope scope(isolate); | 118 for (SharedFunctionInfo* info : sorted) { |
96 SharedFunctionInfo::ScriptIterator infos(Handle<Script>(script, isolate)); | 119 int start = StartPosition(info); |
97 while (SharedFunctionInfo* info = infos.Next()) { | |
98 int start = info->function_token_position(); | |
99 if (start == kNoSourcePosition) start = info->start_position(); | |
100 int end = info->end_position(); | 120 int end = info->end_position(); |
101 uint32_t count = counter_map.Get(info); | 121 uint32_t count = counter_map.Get(info); |
102 if (info->is_toplevel()) { | 122 if (info->is_toplevel()) { |
103 // Top-level function is available. | 123 // Top-level function is available. |
104 DCHECK_EQ(1, stack.size()); | 124 DCHECK_EQ(1, stack.size()); |
105 result.back().toplevel.start = start; | 125 result.back().toplevel.start = start; |
106 result.back().toplevel.end = end; | 126 result.back().toplevel.end = end; |
107 result.back().toplevel.count = count; | 127 result.back().toplevel.count = count; |
108 } else { | 128 } else { |
109 // The shared function infos are sorted by start. | 129 // The shared function infos are sorted by start. |
110 DCHECK_LE(stack.back()->start, start); | 130 DCHECK_LE(stack.back()->start, start); |
111 // Drop the stack to the outer function. | 131 // Drop the stack to the outer function. |
112 while (start > stack.back()->end) stack.pop_back(); | 132 while (start >= stack.back()->end) stack.pop_back(); |
113 Range* outer = stack.back(); | 133 Range* outer = stack.back(); |
114 // New nested function. | 134 // New nested function. |
115 DCHECK_LE(end, outer->end); | 135 DCHECK_LE(end, outer->end); |
116 outer->inner.emplace_back(start, end, count); | 136 outer->inner.emplace_back(start, end, count); |
117 Range& nested = outer->inner.back(); | 137 Range& nested = outer->inner.back(); |
118 String* name = info->DebugName(); | 138 String* name = info->DebugName(); |
119 nested.name.resize(name->length()); | 139 nested.name.resize(name->length()); |
120 String::WriteToFlat(name, nested.name.data(), 0, name->length()); | 140 String::WriteToFlat(name, nested.name.data(), 0, name->length()); |
121 stack.push_back(&nested); | 141 stack.push_back(&nested); |
122 } | 142 } |
123 } | 143 } |
124 stack.clear(); | |
125 } | 144 } |
126 return result; | 145 return result; |
127 } | 146 } |
128 | 147 |
129 void Coverage::EnablePrecise(Isolate* isolate) { | 148 void Coverage::EnablePrecise(Isolate* isolate) { |
130 HandleScope scope(isolate); | 149 HandleScope scope(isolate); |
131 // Remove all optimized function. Optimized and inlined functions do not | 150 // Remove all optimized function. Optimized and inlined functions do not |
132 // increment invocation count. | 151 // increment invocation count. |
133 Deoptimizer::DeoptimizeAll(isolate); | 152 Deoptimizer::DeoptimizeAll(isolate); |
134 // Collect existing feedback vectors. | 153 // Collect existing feedback vectors. |
(...skipping 15 matching lines...) Expand all Loading... |
150 for (const auto& vector : vectors) list = ArrayList::Add(list, vector); | 169 for (const auto& vector : vectors) list = ArrayList::Add(list, vector); |
151 isolate->SetCodeCoverageList(*list); | 170 isolate->SetCodeCoverageList(*list); |
152 } | 171 } |
153 | 172 |
154 void Coverage::DisablePrecise(Isolate* isolate) { | 173 void Coverage::DisablePrecise(Isolate* isolate) { |
155 isolate->SetCodeCoverageList(isolate->heap()->undefined_value()); | 174 isolate->SetCodeCoverageList(isolate->heap()->undefined_value()); |
156 } | 175 } |
157 | 176 |
158 } // namespace internal | 177 } // namespace internal |
159 } // namespace v8 | 178 } // namespace v8 |
OLD | NEW |