Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(856)

Side by Side Diff: runtime/vm/coverage.cc

Issue 1846443002: - Remove --coverage_dir flag and old-style coverage service requests. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Remove obsolete tests. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/coverage.h ('k') | runtime/vm/coverage_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #include "vm/coverage.h"
6
7 #include "include/dart_api.h"
8
9 #include "vm/compiler.h"
10 #include "vm/isolate.h"
11 #include "vm/json_stream.h"
12 #include "vm/longjump.h"
13 #include "vm/object.h"
14 #include "vm/object_store.h"
15
16 namespace dart {
17
18 DEFINE_FLAG(charp, coverage_dir, NULL,
19 "Enable writing coverage data into specified directory.");
20
21
22 class CoverageFilterAll : public CoverageFilter {
23 public:
24 bool ShouldOutputCoverageFor(const Library& lib,
25 const Script& script,
26 const Class& cls,
27 const Function& func) const {
28 return true;
29 }
30 };
31
32
33 // map[token_pos] -> line-number.
34 static void ComputeTokenPosToLineNumberMap(const Script& script,
35 GrowableArray<intptr_t>* map) {
36 const TokenStream& tkns = TokenStream::Handle(script.tokens());
37 const intptr_t len = ExternalTypedData::Handle(tkns.GetStream()).Length();
38 map->SetLength(len);
39 #if defined(DEBUG)
40 for (intptr_t i = 0; i < len; i++) {
41 (*map)[i] = -1;
42 }
43 #endif
44 TokenStream::Iterator tkit(tkns,
45 TokenPosition::kMinSource,
46 TokenStream::Iterator::kAllTokens);
47 intptr_t cur_line = script.line_offset() + 1;
48 while (tkit.CurrentTokenKind() != Token::kEOS) {
49 const intptr_t position = tkit.CurrentPosition().Pos();
50 (*map)[position] = cur_line;
51 if (tkit.CurrentTokenKind() == Token::kNEWLINE) {
52 cur_line++;
53 }
54 tkit.Advance();
55 }
56 }
57
58
59 void CodeCoverage::CompileAndAdd(const Function& function,
60 const JSONArray& hits_or_sites,
61 const GrowableArray<intptr_t>& pos_to_line,
62 bool as_call_sites) {
63 if (!FLAG_support_coverage) {
64 return;
65 }
66 // If the function should not be compiled for coverage analysis, then just
67 // skip this method.
68 // TODO(iposva): Maybe we should skip synthesized methods in general too.
69 if (function.is_abstract() || function.IsRedirectingFactory()) {
70 return;
71 }
72 if (function.IsNonImplicitClosureFunction() &&
73 (function.context_scope() == ContextScope::null())) {
74 // TODO(iposva): This can arise if we attempt to compile an inner function
75 // before we have compiled its enclosing function or if the enclosing
76 // function failed to compile.
77 return;
78 }
79 Thread* thread = Thread::Current();
80 Zone* zone = thread->zone();
81 // Make sure we have the unoptimized code for this function available.
82 if (Compiler::EnsureUnoptimizedCode(thread, function) != Error::null()) {
83 // Ignore the error and this function entirely.
84 return;
85 }
86 const Code& code = Code::Handle(zone, function.unoptimized_code());
87 ASSERT(!code.IsNull());
88
89 // Print the hit counts for all IC datas.
90 ZoneGrowableArray<const ICData*>* ic_data_array =
91 new(zone) ZoneGrowableArray<const ICData*>();
92 function.RestoreICDataMap(ic_data_array, false /* clone ic-data */);
93 const PcDescriptors& descriptors = PcDescriptors::Handle(
94 zone, code.pc_descriptors());
95
96 const TokenPosition begin_pos = function.token_pos();
97 const TokenPosition end_pos = function.end_token_pos();
98 intptr_t last_line = -1;
99 intptr_t last_count = 0;
100 // Only IC based calls have counting.
101 PcDescriptors::Iterator iter(descriptors,
102 RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall);
103 while (iter.MoveNext()) {
104 HANDLESCOPE(thread);
105 const ICData* ic_data = (*ic_data_array)[iter.DeoptId()];
106 if (!ic_data->IsNull()) {
107 const TokenPosition token_pos = iter.TokenPos();
108 // Filter out descriptors that do not map to tokens in the source code.
109 if ((token_pos < begin_pos) || (token_pos > end_pos)) {
110 continue;
111 }
112 if (as_call_sites) {
113 bool is_static_call = iter.Kind() == RawPcDescriptors::kUnoptStaticCall;
114 ic_data->PrintToJSONArray(hits_or_sites,
115 token_pos,
116 is_static_call);
117 } else {
118 intptr_t line = pos_to_line[token_pos.Pos()];
119 #if defined(DEBUG)
120 const Script& script = Script::Handle(zone, function.script());
121 intptr_t test_line = -1;
122 script.GetTokenLocation(token_pos, &test_line, NULL);
123 ASSERT(test_line == line);
124 #endif
125 // Merge hit data where possible.
126 if (last_line == line) {
127 last_count += ic_data->AggregateCount();
128 } else {
129 if ((last_line != -1)) {
130 hits_or_sites.AddValue(last_line);
131 hits_or_sites.AddValue(last_count);
132 }
133 last_count = ic_data->AggregateCount();
134 last_line = line;
135 }
136 }
137 }
138 }
139 // Write last hit value if needed.
140 if (!as_call_sites && (last_line != -1)) {
141 hits_or_sites.AddValue(last_line);
142 hits_or_sites.AddValue(last_count);
143 }
144 }
145
146
147 void CodeCoverage::PrintClass(const Library& lib,
148 const Class& cls,
149 const JSONArray& jsarr,
150 CoverageFilter* filter,
151 bool as_call_sites) {
152 if (!FLAG_support_coverage) {
153 return;
154 }
155 Thread* thread = Thread::Current();
156 if (cls.EnsureIsFinalized(thread) != Error::null()) {
157 // Only classes that have been finalized do have a meaningful list of
158 // functions.
159 return;
160 }
161 Array& functions = Array::Handle(cls.functions());
162 ASSERT(!functions.IsNull());
163 Function& function = Function::Handle();
164 Script& script = Script::Handle();
165 String& saved_url = String::Handle();
166 String& url = String::Handle();
167 GrowableArray<intptr_t> pos_to_line;
168 int i = 0;
169 while (i < functions.Length()) {
170 HANDLESCOPE(thread);
171 function ^= functions.At(i);
172 script = function.script();
173 saved_url = script.url();
174 if (!filter->ShouldOutputCoverageFor(lib, script, cls, function)) {
175 i++;
176 continue;
177 }
178 if (!as_call_sites) {
179 ComputeTokenPosToLineNumberMap(script, &pos_to_line);
180 }
181 JSONObject jsobj(&jsarr);
182 jsobj.AddProperty("source", saved_url.ToCString());
183 jsobj.AddProperty("script", script);
184 JSONArray hits_or_sites(&jsobj, as_call_sites ? "callSites" : "hits");
185
186 // We stay within this loop while we are seeing functions from the same
187 // source URI.
188 while (i < functions.Length()) {
189 function ^= functions.At(i);
190 script = function.script();
191 url = script.url();
192 if (!url.Equals(saved_url)) {
193 pos_to_line.Clear();
194 break;
195 }
196 if (!filter->ShouldOutputCoverageFor(lib, script, cls, function)) {
197 i++;
198 continue;
199 }
200 CompileAndAdd(function, hits_or_sites, pos_to_line, as_call_sites);
201 i++;
202 }
203 }
204
205 // TODO(turnidge): This looks like it prints closures many, many times.
206 const GrowableObjectArray& closures = GrowableObjectArray::Handle(
207 thread->isolate()->object_store()->closure_functions());
208 pos_to_line.Clear();
209 // We need to keep rechecking the length of the closures array, as handling
210 // a closure potentially adds new entries to the end.
211 i = 0;
212 while (i < closures.Length()) {
213 HANDLESCOPE(thread);
214 function ^= closures.At(i);
215 if (function.Owner() != cls.raw()) {
216 i++;
217 continue;
218 }
219 script = function.script();
220 saved_url = script.url();
221 if (!filter->ShouldOutputCoverageFor(lib, script, cls, function)) {
222 i++;
223 continue;
224 }
225 ComputeTokenPosToLineNumberMap(script, &pos_to_line);
226 JSONObject jsobj(&jsarr);
227 jsobj.AddProperty("source", saved_url.ToCString());
228 jsobj.AddProperty("script", script);
229 JSONArray hits_or_sites(&jsobj, as_call_sites ? "callSites" : "hits");
230
231 // We stay within this loop while we are seeing functions from the same
232 // source URI.
233 while (i < closures.Length()) {
234 function ^= closures.At(i);
235 script = function.script();
236 url = script.url();
237 if (!url.Equals(saved_url)) {
238 pos_to_line.Clear();
239 break;
240 }
241 CompileAndAdd(function, hits_or_sites, pos_to_line, as_call_sites);
242 i++;
243 }
244 }
245 }
246
247
248 void CodeCoverage::Write(Thread* thread) {
249 if (!FLAG_support_coverage) {
250 return;
251 }
252 if (FLAG_coverage_dir == NULL) {
253 return;
254 }
255
256 Dart_FileOpenCallback file_open = Dart::file_open_callback();
257 Dart_FileWriteCallback file_write = Dart::file_write_callback();
258 Dart_FileCloseCallback file_close = Dart::file_close_callback();
259 if ((file_open == NULL) || (file_write == NULL) || (file_close == NULL)) {
260 return;
261 }
262
263 JSONStream stream;
264 PrintJSON(thread, &stream, NULL, false);
265
266 intptr_t pid = OS::ProcessId();
267 char* filename = OS::SCreate(thread->zone(),
268 "%s/dart-cov-%" Pd "-%" Pd64 ".json",
269 FLAG_coverage_dir, pid, thread->isolate()->main_port());
270 void* file = (*file_open)(filename, true);
271 if (file == NULL) {
272 OS::Print("Failed to write coverage file: %s\n", filename);
273 return;
274 }
275 (*file_write)(stream.buffer()->buf(), stream.buffer()->length(), file);
276 (*file_close)(file);
277 }
278
279
280 void CodeCoverage::PrintJSON(Thread* thread,
281 JSONStream* stream,
282 CoverageFilter* filter,
283 bool as_call_sites) {
284 if (!FLAG_support_coverage) {
285 return;
286 }
287 CoverageFilterAll default_filter;
288 if (filter == NULL) {
289 filter = &default_filter;
290 }
291 const GrowableObjectArray& libs = GrowableObjectArray::Handle(
292 thread->zone(),
293 thread->isolate()->object_store()->libraries());
294 Library& lib = Library::Handle();
295 Class& cls = Class::Handle();
296 JSONObject coverage(stream);
297 coverage.AddProperty("type", "CodeCoverage");
298 {
299 JSONArray jsarr(&coverage, "coverage");
300 for (int i = 0; i < libs.Length(); i++) {
301 lib ^= libs.At(i);
302 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
303 while (it.HasNext()) {
304 cls = it.GetNextClass();
305 ASSERT(!cls.IsNull());
306 PrintClass(lib, cls, jsarr, filter, as_call_sites);
307 }
308 }
309 }
310 }
311
312
313 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/coverage.h ('k') | runtime/vm/coverage_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698