OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 #ifndef PRODUCT | 4 #ifndef PRODUCT |
5 #include "vm/source_report.h" | 5 #include "vm/source_report.h" |
6 | 6 |
7 #include "vm/compiler.h" | 7 #include "vm/compiler.h" |
8 #include "vm/isolate.h" | 8 #include "vm/isolate.h" |
9 #include "vm/object.h" | 9 #include "vm/object.h" |
10 #include "vm/object_store.h" | 10 #include "vm/object_store.h" |
(...skipping 10 matching lines...) Expand all Loading... |
21 SourceReport::SourceReport(intptr_t report_set, CompileMode compile_mode) | 21 SourceReport::SourceReport(intptr_t report_set, CompileMode compile_mode) |
22 : report_set_(report_set), | 22 : report_set_(report_set), |
23 compile_mode_(compile_mode), | 23 compile_mode_(compile_mode), |
24 thread_(NULL), | 24 thread_(NULL), |
25 script_(NULL), | 25 script_(NULL), |
26 start_pos_(TokenPosition::kNoSource), | 26 start_pos_(TokenPosition::kNoSource), |
27 end_pos_(TokenPosition::kNoSource), | 27 end_pos_(TokenPosition::kNoSource), |
28 profile_(Isolate::Current()), | 28 profile_(Isolate::Current()), |
29 next_script_index_(0) {} | 29 next_script_index_(0) {} |
30 | 30 |
31 | |
32 SourceReport::~SourceReport() { | 31 SourceReport::~SourceReport() { |
33 ClearScriptTable(); | 32 ClearScriptTable(); |
34 } | 33 } |
35 | 34 |
36 | |
37 void SourceReport::ClearScriptTable() { | 35 void SourceReport::ClearScriptTable() { |
38 for (intptr_t i = 0; i < script_table_entries_.length(); i++) { | 36 for (intptr_t i = 0; i < script_table_entries_.length(); i++) { |
39 delete script_table_entries_[i]; | 37 delete script_table_entries_[i]; |
40 script_table_entries_[i] = NULL; | 38 script_table_entries_[i] = NULL; |
41 } | 39 } |
42 script_table_entries_.Clear(); | 40 script_table_entries_.Clear(); |
43 script_table_.Clear(); | 41 script_table_.Clear(); |
44 next_script_index_ = 0; | 42 next_script_index_ = 0; |
45 } | 43 } |
46 | 44 |
47 | |
48 void SourceReport::Init(Thread* thread, | 45 void SourceReport::Init(Thread* thread, |
49 const Script* script, | 46 const Script* script, |
50 TokenPosition start_pos, | 47 TokenPosition start_pos, |
51 TokenPosition end_pos) { | 48 TokenPosition end_pos) { |
52 thread_ = thread; | 49 thread_ = thread; |
53 script_ = script; | 50 script_ = script; |
54 start_pos_ = start_pos; | 51 start_pos_ = start_pos; |
55 end_pos_ = end_pos; | 52 end_pos_ = end_pos; |
56 ClearScriptTable(); | 53 ClearScriptTable(); |
57 if (IsReportRequested(kProfile)) { | 54 if (IsReportRequested(kProfile)) { |
58 // Build the profile. | 55 // Build the profile. |
59 SampleFilter samplesForIsolate(thread_->isolate()->main_port(), | 56 SampleFilter samplesForIsolate(thread_->isolate()->main_port(), |
60 Thread::kMutatorTask, -1, -1); | 57 Thread::kMutatorTask, -1, -1); |
61 profile_.Build(thread, &samplesForIsolate, Profiler::sample_buffer(), | 58 profile_.Build(thread, &samplesForIsolate, Profiler::sample_buffer(), |
62 Profile::kNoTags); | 59 Profile::kNoTags); |
63 } | 60 } |
64 } | 61 } |
65 | 62 |
66 | |
67 bool SourceReport::IsReportRequested(ReportKind report_kind) { | 63 bool SourceReport::IsReportRequested(ReportKind report_kind) { |
68 return (report_set_ & report_kind) != 0; | 64 return (report_set_ & report_kind) != 0; |
69 } | 65 } |
70 | 66 |
71 | |
72 bool SourceReport::ShouldSkipFunction(const Function& func) { | 67 bool SourceReport::ShouldSkipFunction(const Function& func) { |
73 if (script_ != NULL && !script_->IsNull()) { | 68 if (script_ != NULL && !script_->IsNull()) { |
74 if (func.script() != script_->raw()) { | 69 if (func.script() != script_->raw()) { |
75 // The function is from the wrong script. | 70 // The function is from the wrong script. |
76 return true; | 71 return true; |
77 } | 72 } |
78 if (((start_pos_ > TokenPosition::kMinSource) && | 73 if (((start_pos_ > TokenPosition::kMinSource) && |
79 (func.end_token_pos() < start_pos_)) || | 74 (func.end_token_pos() < start_pos_)) || |
80 ((end_pos_ > TokenPosition::kMinSource) && | 75 ((end_pos_ > TokenPosition::kMinSource) && |
81 (func.token_pos() > end_pos_))) { | 76 (func.token_pos() > end_pos_))) { |
(...skipping 19 matching lines...) Expand all Loading... |
101 if (func.IsNonImplicitClosureFunction() && | 96 if (func.IsNonImplicitClosureFunction() && |
102 (func.context_scope() == ContextScope::null())) { | 97 (func.context_scope() == ContextScope::null())) { |
103 // TODO(iposva): This can arise if we attempt to compile an inner function | 98 // TODO(iposva): This can arise if we attempt to compile an inner function |
104 // before we have compiled its enclosing function or if the enclosing | 99 // before we have compiled its enclosing function or if the enclosing |
105 // function failed to compile. | 100 // function failed to compile. |
106 return true; | 101 return true; |
107 } | 102 } |
108 return false; | 103 return false; |
109 } | 104 } |
110 | 105 |
111 | |
112 intptr_t SourceReport::GetScriptIndex(const Script& script) { | 106 intptr_t SourceReport::GetScriptIndex(const Script& script) { |
113 const String& url = String::Handle(zone(), script.url()); | 107 const String& url = String::Handle(zone(), script.url()); |
114 ScriptTableEntry* pair = script_table_.LookupValue(&url); | 108 ScriptTableEntry* pair = script_table_.LookupValue(&url); |
115 if (pair != NULL) { | 109 if (pair != NULL) { |
116 return pair->index; | 110 return pair->index; |
117 } | 111 } |
118 ScriptTableEntry* tmp = new ScriptTableEntry(); | 112 ScriptTableEntry* tmp = new ScriptTableEntry(); |
119 tmp->key = &url; | 113 tmp->key = &url; |
120 tmp->index = next_script_index_++; | 114 tmp->index = next_script_index_++; |
121 tmp->script = &Script::Handle(zone(), script.raw()); | 115 tmp->script = &Script::Handle(zone(), script.raw()); |
122 script_table_entries_.Add(tmp); | 116 script_table_entries_.Add(tmp); |
123 script_table_.Insert(tmp); | 117 script_table_.Insert(tmp); |
124 ASSERT(script_table_entries_.length() == next_script_index_); | 118 ASSERT(script_table_entries_.length() == next_script_index_); |
125 #if defined(DEBUG) | 119 #if defined(DEBUG) |
126 VerifyScriptTable(); | 120 VerifyScriptTable(); |
127 #endif | 121 #endif |
128 return tmp->index; | 122 return tmp->index; |
129 } | 123 } |
130 | 124 |
131 | |
132 #if defined(DEBUG) | 125 #if defined(DEBUG) |
133 void SourceReport::VerifyScriptTable() { | 126 void SourceReport::VerifyScriptTable() { |
134 for (intptr_t i = 0; i < script_table_entries_.length(); i++) { | 127 for (intptr_t i = 0; i < script_table_entries_.length(); i++) { |
135 const String* url = script_table_entries_[i]->key; | 128 const String* url = script_table_entries_[i]->key; |
136 const Script* script = script_table_entries_[i]->script; | 129 const Script* script = script_table_entries_[i]->script; |
137 intptr_t index = script_table_entries_[i]->index; | 130 intptr_t index = script_table_entries_[i]->index; |
138 ASSERT(i == index); | 131 ASSERT(i == index); |
139 const String& url2 = String::Handle(zone(), script->url()); | 132 const String& url2 = String::Handle(zone(), script->url()); |
140 ASSERT(url2.Equals(*url)); | 133 ASSERT(url2.Equals(*url)); |
141 ScriptTableEntry* pair = script_table_.LookupValue(&url2); | 134 ScriptTableEntry* pair = script_table_.LookupValue(&url2); |
142 ASSERT(i == pair->index); | 135 ASSERT(i == pair->index); |
143 } | 136 } |
144 } | 137 } |
145 #endif | 138 #endif |
146 | 139 |
147 | |
148 bool SourceReport::ScriptIsLoadedByLibrary(const Script& script, | 140 bool SourceReport::ScriptIsLoadedByLibrary(const Script& script, |
149 const Library& lib) { | 141 const Library& lib) { |
150 const Array& scripts = Array::Handle(zone(), lib.LoadedScripts()); | 142 const Array& scripts = Array::Handle(zone(), lib.LoadedScripts()); |
151 for (intptr_t j = 0; j < scripts.Length(); j++) { | 143 for (intptr_t j = 0; j < scripts.Length(); j++) { |
152 if (scripts.At(j) == script.raw()) { | 144 if (scripts.At(j) == script.raw()) { |
153 return true; | 145 return true; |
154 } | 146 } |
155 } | 147 } |
156 return false; | 148 return false; |
157 } | 149 } |
158 | 150 |
159 | |
160 void SourceReport::PrintCallSitesData(JSONObject* jsobj, | 151 void SourceReport::PrintCallSitesData(JSONObject* jsobj, |
161 const Function& function, | 152 const Function& function, |
162 const Code& code) { | 153 const Code& code) { |
163 const TokenPosition begin_pos = function.token_pos(); | 154 const TokenPosition begin_pos = function.token_pos(); |
164 const TokenPosition end_pos = function.end_token_pos(); | 155 const TokenPosition end_pos = function.end_token_pos(); |
165 | 156 |
166 ZoneGrowableArray<const ICData*>* ic_data_array = | 157 ZoneGrowableArray<const ICData*>* ic_data_array = |
167 new (zone()) ZoneGrowableArray<const ICData*>(); | 158 new (zone()) ZoneGrowableArray<const ICData*>(); |
168 function.RestoreICDataMap(ic_data_array, false /* clone ic-data */); | 159 function.RestoreICDataMap(ic_data_array, false /* clone ic-data */); |
169 const PcDescriptors& descriptors = | 160 const PcDescriptors& descriptors = |
(...skipping 19 matching lines...) Expand all Loading... |
189 const TokenPosition token_pos = iter.TokenPos(); | 180 const TokenPosition token_pos = iter.TokenPos(); |
190 if ((token_pos < begin_pos) || (token_pos > end_pos)) { | 181 if ((token_pos < begin_pos) || (token_pos > end_pos)) { |
191 // Does not correspond to a valid source position. | 182 // Does not correspond to a valid source position. |
192 continue; | 183 continue; |
193 } | 184 } |
194 ic_data->PrintToJSONArray(sites, token_pos); | 185 ic_data->PrintToJSONArray(sites, token_pos); |
195 } | 186 } |
196 } | 187 } |
197 } | 188 } |
198 | 189 |
199 | |
200 void SourceReport::PrintCoverageData(JSONObject* jsobj, | 190 void SourceReport::PrintCoverageData(JSONObject* jsobj, |
201 const Function& function, | 191 const Function& function, |
202 const Code& code) { | 192 const Code& code) { |
203 const TokenPosition begin_pos = function.token_pos(); | 193 const TokenPosition begin_pos = function.token_pos(); |
204 const TokenPosition end_pos = function.end_token_pos(); | 194 const TokenPosition end_pos = function.end_token_pos(); |
205 | 195 |
206 ZoneGrowableArray<const ICData*>* ic_data_array = | 196 ZoneGrowableArray<const ICData*>* ic_data_array = |
207 new (zone()) ZoneGrowableArray<const ICData*>(); | 197 new (zone()) ZoneGrowableArray<const ICData*>(); |
208 function.RestoreICDataMap(ic_data_array, false /* clone ic-data */); | 198 function.RestoreICDataMap(ic_data_array, false /* clone ic-data */); |
209 const PcDescriptors& descriptors = | 199 const PcDescriptors& descriptors = |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 JSONArray misses(&cov, "misses"); | 256 JSONArray misses(&cov, "misses"); |
267 for (int i = 0; i < func_length; i++) { | 257 for (int i = 0; i < func_length; i++) { |
268 if (coverage[i] == kCoverageMiss) { | 258 if (coverage[i] == kCoverageMiss) { |
269 // Add the token position of the miss. | 259 // Add the token position of the miss. |
270 misses.AddValue(begin_pos.Pos() + i); | 260 misses.AddValue(begin_pos.Pos() + i); |
271 } | 261 } |
272 } | 262 } |
273 } | 263 } |
274 } | 264 } |
275 | 265 |
276 | |
277 void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj, | 266 void SourceReport::PrintPossibleBreakpointsData(JSONObject* jsobj, |
278 const Function& func, | 267 const Function& func, |
279 const Code& code) { | 268 const Code& code) { |
280 const uint8_t kSafepointKind = | 269 const uint8_t kSafepointKind = |
281 (RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall | | 270 (RawPcDescriptors::kIcCall | RawPcDescriptors::kUnoptStaticCall | |
282 RawPcDescriptors::kRuntimeCall); | 271 RawPcDescriptors::kRuntimeCall); |
283 const TokenPosition begin_pos = func.token_pos(); | 272 const TokenPosition begin_pos = func.token_pos(); |
284 const TokenPosition end_pos = func.end_token_pos(); | 273 const TokenPosition end_pos = func.end_token_pos(); |
285 | 274 |
286 const PcDescriptors& descriptors = | 275 const PcDescriptors& descriptors = |
(...skipping 19 matching lines...) Expand all Loading... |
306 | 295 |
307 JSONArray bpts(jsobj, "possibleBreakpoints"); | 296 JSONArray bpts(jsobj, "possibleBreakpoints"); |
308 for (int i = 0; i < func_length; i++) { | 297 for (int i = 0; i < func_length; i++) { |
309 if (possible[i]) { | 298 if (possible[i]) { |
310 // Add the token position. | 299 // Add the token position. |
311 bpts.AddValue(begin_pos.Pos() + i); | 300 bpts.AddValue(begin_pos.Pos() + i); |
312 } | 301 } |
313 } | 302 } |
314 } | 303 } |
315 | 304 |
316 | |
317 void SourceReport::PrintProfileData(JSONObject* jsobj, | 305 void SourceReport::PrintProfileData(JSONObject* jsobj, |
318 ProfileFunction* profile_function) { | 306 ProfileFunction* profile_function) { |
319 ASSERT(profile_function != NULL); | 307 ASSERT(profile_function != NULL); |
320 ASSERT(profile_function->NumSourcePositions() > 0); | 308 ASSERT(profile_function->NumSourcePositions() > 0); |
321 | 309 |
322 { | 310 { |
323 JSONObject profile(jsobj, "profile"); | 311 JSONObject profile(jsobj, "profile"); |
324 | 312 |
325 { | 313 { |
326 JSONObject profileData(&profile, "metadata"); | 314 JSONObject profileData(&profile, "metadata"); |
(...skipping 30 matching lines...) Expand all Loading... |
357 JSONArray inclusiveTicks(&profile, "inclusiveTicks"); | 345 JSONArray inclusiveTicks(&profile, "inclusiveTicks"); |
358 for (intptr_t i = 0; i < profile_function->NumSourcePositions(); i++) { | 346 for (intptr_t i = 0; i < profile_function->NumSourcePositions(); i++) { |
359 const ProfileFunctionSourcePosition& position = | 347 const ProfileFunctionSourcePosition& position = |
360 profile_function->GetSourcePosition(i); | 348 profile_function->GetSourcePosition(i); |
361 inclusiveTicks.AddValue(position.inclusive_ticks()); | 349 inclusiveTicks.AddValue(position.inclusive_ticks()); |
362 } | 350 } |
363 } | 351 } |
364 } | 352 } |
365 } | 353 } |
366 | 354 |
367 | |
368 void SourceReport::PrintScriptTable(JSONArray* scripts) { | 355 void SourceReport::PrintScriptTable(JSONArray* scripts) { |
369 for (intptr_t i = 0; i < script_table_entries_.length(); i++) { | 356 for (intptr_t i = 0; i < script_table_entries_.length(); i++) { |
370 const Script* script = script_table_entries_[i]->script; | 357 const Script* script = script_table_entries_[i]->script; |
371 scripts->AddValue(*script); | 358 scripts->AddValue(*script); |
372 } | 359 } |
373 } | 360 } |
374 | 361 |
375 | |
376 void SourceReport::VisitFunction(JSONArray* jsarr, const Function& func) { | 362 void SourceReport::VisitFunction(JSONArray* jsarr, const Function& func) { |
377 if (ShouldSkipFunction(func)) { | 363 if (ShouldSkipFunction(func)) { |
378 return; | 364 return; |
379 } | 365 } |
380 | 366 |
381 const Script& script = Script::Handle(zone(), func.script()); | 367 const Script& script = Script::Handle(zone(), func.script()); |
382 const TokenPosition begin_pos = func.token_pos(); | 368 const TokenPosition begin_pos = func.token_pos(); |
383 const TokenPosition end_pos = func.end_token_pos(); | 369 const TokenPosition end_pos = func.end_token_pos(); |
384 | 370 |
385 Code& code = Code::Handle(zone(), func.unoptimized_code()); | 371 Code& code = Code::Handle(zone(), func.unoptimized_code()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
435 } | 421 } |
436 if (IsReportRequested(kProfile)) { | 422 if (IsReportRequested(kProfile)) { |
437 ProfileFunction* profile_function = profile_.FindFunction(func); | 423 ProfileFunction* profile_function = profile_.FindFunction(func); |
438 if ((profile_function != NULL) && | 424 if ((profile_function != NULL) && |
439 (profile_function->NumSourcePositions() > 0)) { | 425 (profile_function->NumSourcePositions() > 0)) { |
440 PrintProfileData(&range, profile_function); | 426 PrintProfileData(&range, profile_function); |
441 } | 427 } |
442 } | 428 } |
443 } | 429 } |
444 | 430 |
445 | |
446 void SourceReport::VisitLibrary(JSONArray* jsarr, const Library& lib) { | 431 void SourceReport::VisitLibrary(JSONArray* jsarr, const Library& lib) { |
447 Class& cls = Class::Handle(zone()); | 432 Class& cls = Class::Handle(zone()); |
448 Array& functions = Array::Handle(zone()); | 433 Array& functions = Array::Handle(zone()); |
449 Function& func = Function::Handle(zone()); | 434 Function& func = Function::Handle(zone()); |
450 Script& script = Script::Handle(zone()); | 435 Script& script = Script::Handle(zone()); |
451 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | 436 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); |
452 while (it.HasNext()) { | 437 while (it.HasNext()) { |
453 cls = it.GetNextClass(); | 438 cls = it.GetNextClass(); |
454 if (!cls.is_finalized()) { | 439 if (!cls.is_finalized()) { |
455 if (compile_mode_ == kForceCompile) { | 440 if (compile_mode_ == kForceCompile) { |
(...skipping 22 matching lines...) Expand all Loading... |
478 } | 463 } |
479 | 464 |
480 functions = cls.functions(); | 465 functions = cls.functions(); |
481 for (int i = 0; i < functions.Length(); i++) { | 466 for (int i = 0; i < functions.Length(); i++) { |
482 func ^= functions.At(i); | 467 func ^= functions.At(i); |
483 VisitFunction(jsarr, func); | 468 VisitFunction(jsarr, func); |
484 } | 469 } |
485 } | 470 } |
486 } | 471 } |
487 | 472 |
488 | |
489 void SourceReport::VisitClosures(JSONArray* jsarr) { | 473 void SourceReport::VisitClosures(JSONArray* jsarr) { |
490 const GrowableObjectArray& closures = GrowableObjectArray::Handle( | 474 const GrowableObjectArray& closures = GrowableObjectArray::Handle( |
491 thread()->isolate()->object_store()->closure_functions()); | 475 thread()->isolate()->object_store()->closure_functions()); |
492 | 476 |
493 // We need to keep rechecking the length of the closures array, as handling | 477 // We need to keep rechecking the length of the closures array, as handling |
494 // a closure potentially adds new entries to the end. | 478 // a closure potentially adds new entries to the end. |
495 Function& func = Function::Handle(zone()); | 479 Function& func = Function::Handle(zone()); |
496 for (int i = 0; i < closures.Length(); i++) { | 480 for (int i = 0; i < closures.Length(); i++) { |
497 func ^= closures.At(i); | 481 func ^= closures.At(i); |
498 VisitFunction(jsarr, func); | 482 VisitFunction(jsarr, func); |
499 } | 483 } |
500 } | 484 } |
501 | 485 |
502 | |
503 void SourceReport::PrintJSON(JSONStream* js, | 486 void SourceReport::PrintJSON(JSONStream* js, |
504 const Script& script, | 487 const Script& script, |
505 TokenPosition start_pos, | 488 TokenPosition start_pos, |
506 TokenPosition end_pos) { | 489 TokenPosition end_pos) { |
507 Init(Thread::Current(), &script, start_pos, end_pos); | 490 Init(Thread::Current(), &script, start_pos, end_pos); |
508 | 491 |
509 JSONObject report(js); | 492 JSONObject report(js); |
510 report.AddProperty("type", "SourceReport"); | 493 report.AddProperty("type", "SourceReport"); |
511 { | 494 { |
512 JSONArray ranges(&report, "ranges"); | 495 JSONArray ranges(&report, "ranges"); |
(...skipping 14 matching lines...) Expand all Loading... |
527 VisitClosures(&ranges); | 510 VisitClosures(&ranges); |
528 } | 511 } |
529 | 512 |
530 // Print the script table. | 513 // Print the script table. |
531 JSONArray scripts(&report, "scripts"); | 514 JSONArray scripts(&report, "scripts"); |
532 PrintScriptTable(&scripts); | 515 PrintScriptTable(&scripts); |
533 } | 516 } |
534 | 517 |
535 } // namespace dart | 518 } // namespace dart |
536 #endif // PRODUCT | 519 #endif // PRODUCT |
OLD | NEW |