| 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 |