Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/profile-generator-inl.h" | 7 #include "src/profile-generator-inl.h" |
| 8 | 8 |
| 9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
| 10 #include "src/debug.h" | 10 #include "src/debug.h" |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 137 } | 137 } |
| 138 | 138 |
| 139 | 139 |
| 140 const char* const CodeEntry::kEmptyNamePrefix = ""; | 140 const char* const CodeEntry::kEmptyNamePrefix = ""; |
| 141 const char* const CodeEntry::kEmptyResourceName = ""; | 141 const char* const CodeEntry::kEmptyResourceName = ""; |
| 142 const char* const CodeEntry::kEmptyBailoutReason = ""; | 142 const char* const CodeEntry::kEmptyBailoutReason = ""; |
| 143 | 143 |
| 144 | 144 |
| 145 CodeEntry::~CodeEntry() { | 145 CodeEntry::~CodeEntry() { |
| 146 delete no_frame_ranges_; | 146 delete no_frame_ranges_; |
| 147 delete line_info_; | |
| 147 } | 148 } |
| 148 | 149 |
| 149 | 150 |
| 150 uint32_t CodeEntry::GetCallUid() const { | 151 uint32_t CodeEntry::GetCallUid() const { |
| 151 uint32_t hash = ComputeIntegerHash(tag_, v8::internal::kZeroHashSeed); | 152 uint32_t hash = ComputeIntegerHash(tag_, v8::internal::kZeroHashSeed); |
| 152 if (shared_id_ != 0) { | 153 if (shared_id_ != 0) { |
| 153 hash ^= ComputeIntegerHash(static_cast<uint32_t>(shared_id_), | 154 hash ^= ComputeIntegerHash(static_cast<uint32_t>(shared_id_), |
| 154 v8::internal::kZeroHashSeed); | 155 v8::internal::kZeroHashSeed); |
| 155 } else { | 156 } else { |
| 156 hash ^= ComputeIntegerHash( | 157 hash ^= ComputeIntegerHash( |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 179 && line_number_ == entry->line_number_))); | 180 && line_number_ == entry->line_number_))); |
| 180 } | 181 } |
| 181 | 182 |
| 182 | 183 |
| 183 void CodeEntry::SetBuiltinId(Builtins::Name id) { | 184 void CodeEntry::SetBuiltinId(Builtins::Name id) { |
| 184 tag_ = Logger::BUILTIN_TAG; | 185 tag_ = Logger::BUILTIN_TAG; |
| 185 builtin_id_ = id; | 186 builtin_id_ = id; |
| 186 } | 187 } |
| 187 | 188 |
| 188 | 189 |
| 190 int CodeEntry::GetSourceLine(int pc_offset) const { | |
| 191 if (line_info_ && !line_info_->Empty()) { | |
| 192 return line_info_->GetSourceLineNumber(pc_offset); | |
| 193 } | |
| 194 return v8::CpuProfileNode::kNoLineNumberInfo; | |
| 195 } | |
| 196 | |
| 197 | |
| 189 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { | 198 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { |
| 190 HashMap::Entry* map_entry = | 199 HashMap::Entry* map_entry = |
| 191 children_.Lookup(entry, CodeEntryHash(entry), false); | 200 children_.Lookup(entry, CodeEntryHash(entry), false); |
| 192 return map_entry != NULL ? | 201 return map_entry != NULL ? |
| 193 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; | 202 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; |
| 194 } | 203 } |
| 195 | 204 |
| 196 | 205 |
| 197 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { | 206 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { |
| 198 HashMap::Entry* map_entry = | 207 HashMap::Entry* map_entry = |
| 199 children_.Lookup(entry, CodeEntryHash(entry), true); | 208 children_.Lookup(entry, CodeEntryHash(entry), true); |
| 200 if (map_entry->value == NULL) { | 209 if (map_entry->value == NULL) { |
| 201 // New node added. | 210 // New node added. |
| 202 ProfileNode* new_node = new ProfileNode(tree_, entry); | 211 ProfileNode* new_node = new ProfileNode(tree_, entry); |
| 203 map_entry->value = new_node; | 212 map_entry->value = new_node; |
| 204 children_list_.Add(new_node); | 213 children_list_.Add(new_node); |
| 205 } | 214 } |
| 206 return reinterpret_cast<ProfileNode*>(map_entry->value); | 215 return reinterpret_cast<ProfileNode*>(map_entry->value); |
| 207 } | 216 } |
| 208 | 217 |
| 209 | 218 |
| 219 void ProfileNode::IncrementLineTicks(int src_line) { | |
| 220 if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) return; | |
| 221 // Increment a hit counter of a certain source line. | |
| 222 // Add a new source line if not found. | |
| 223 HashMap::Entry* e = | |
| 224 line_ticks_.Lookup(reinterpret_cast<void*>(src_line), src_line, true); | |
| 225 ASSERT(e); | |
| 226 e->value = static_cast<char*>(e->value) + 1; | |
| 227 } | |
| 228 | |
| 229 | |
| 230 bool ProfileNode::GetLineTicks(v8::CpuProfileNode::LineTick* entries, | |
| 231 unsigned int number) const { | |
|
yurys
2014/08/08 08:13:23
nit: number -> length
| |
| 232 if (entries == NULL || number == 0) return false; | |
| 233 | |
| 234 unsigned line_number = line_ticks_.occupancy(); | |
|
yurys
2014/08/08 08:13:23
line_count
| |
| 235 | |
| 236 if (line_number == 0) return false; | |
| 237 if (number < line_number) return false; | |
| 238 | |
| 239 v8::CpuProfileNode::LineTick* entry = entries; | |
| 240 | |
| 241 for (HashMap::Entry* p = line_ticks_.Start(); | |
| 242 p != NULL; | |
| 243 p = line_ticks_.Next(p), entry++) { | |
| 244 entry->line = reinterpret_cast<uintptr_t>(p->key); | |
| 245 entry->hit_count = reinterpret_cast<uintptr_t>(p->value); | |
| 246 } | |
| 247 | |
| 248 return true; | |
| 249 } | |
| 250 | |
| 251 | |
| 210 void ProfileNode::Print(int indent) { | 252 void ProfileNode::Print(int indent) { |
| 211 base::OS::Print("%5u %*s %s%s %d #%d %s", self_ticks_, indent, "", | 253 base::OS::Print("%5u %*s %s%s %d #%d %s", self_ticks_, indent, "", |
| 212 entry_->name_prefix(), entry_->name(), entry_->script_id(), | 254 entry_->name_prefix(), entry_->name(), entry_->script_id(), |
| 213 id(), entry_->bailout_reason()); | 255 id(), entry_->bailout_reason()); |
| 214 if (entry_->resource_name()[0] != '\0') | 256 if (entry_->resource_name()[0] != '\0') |
| 215 base::OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); | 257 base::OS::Print(" %s:%d", entry_->resource_name(), entry_->line_number()); |
| 216 base::OS::Print("\n"); | 258 base::OS::Print("\n"); |
| 217 for (HashMap::Entry* p = children_.Start(); | 259 for (HashMap::Entry* p = children_.Start(); |
| 218 p != NULL; | 260 p != NULL; |
| 219 p = children_.Next(p)) { | 261 p = children_.Next(p)) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 240 root_(new ProfileNode(this, &root_entry_)) { | 282 root_(new ProfileNode(this, &root_entry_)) { |
| 241 } | 283 } |
| 242 | 284 |
| 243 | 285 |
| 244 ProfileTree::~ProfileTree() { | 286 ProfileTree::~ProfileTree() { |
| 245 DeleteNodesCallback cb; | 287 DeleteNodesCallback cb; |
| 246 TraverseDepthFirst(&cb); | 288 TraverseDepthFirst(&cb); |
| 247 } | 289 } |
| 248 | 290 |
| 249 | 291 |
| 250 ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path) { | 292 ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path, |
| 293 int src_line) { | |
| 251 ProfileNode* node = root_; | 294 ProfileNode* node = root_; |
| 252 for (CodeEntry** entry = path.start() + path.length() - 1; | 295 for (CodeEntry** entry = path.start() + path.length() - 1; |
| 253 entry != path.start() - 1; | 296 entry != path.start() - 1; |
| 254 --entry) { | 297 --entry) { |
| 255 if (*entry != NULL) { | 298 if (*entry != NULL) { |
| 256 node = node->FindOrAddChild(*entry); | 299 node = node->FindOrAddChild(*entry); |
| 257 } | 300 } |
| 258 } | 301 } |
| 259 node->IncrementSelfTicks(); | 302 node->IncrementSelfTicks(); |
| 303 if (src_line != v8::CpuProfileNode::kNoLineNumberInfo) { | |
| 304 node->IncrementLineTicks(src_line); | |
| 305 } | |
| 260 return node; | 306 return node; |
| 261 } | 307 } |
| 262 | 308 |
| 263 | 309 |
| 264 void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path) { | 310 void ProfileTree::AddPathFromStart(const Vector<CodeEntry*>& path, |
| 311 int src_line) { | |
| 265 ProfileNode* node = root_; | 312 ProfileNode* node = root_; |
| 266 for (CodeEntry** entry = path.start(); | 313 for (CodeEntry** entry = path.start(); |
| 267 entry != path.start() + path.length(); | 314 entry != path.start() + path.length(); |
| 268 ++entry) { | 315 ++entry) { |
| 269 if (*entry != NULL) { | 316 if (*entry != NULL) { |
| 270 node = node->FindOrAddChild(*entry); | 317 node = node->FindOrAddChild(*entry); |
| 271 } | 318 } |
| 272 } | 319 } |
| 273 node->IncrementSelfTicks(); | 320 node->IncrementSelfTicks(); |
| 321 if (src_line != v8::CpuProfileNode::kNoLineNumberInfo) { | |
| 322 node->IncrementLineTicks(src_line); | |
| 323 } | |
| 274 } | 324 } |
| 275 | 325 |
| 276 | 326 |
| 277 struct NodesPair { | 327 struct NodesPair { |
| 278 NodesPair(ProfileNode* src, ProfileNode* dst) | 328 NodesPair(ProfileNode* src, ProfileNode* dst) |
| 279 : src(src), dst(dst) { } | 329 : src(src), dst(dst) { } |
| 280 ProfileNode* src; | 330 ProfileNode* src; |
| 281 ProfileNode* dst; | 331 ProfileNode* dst; |
| 282 }; | 332 }; |
| 283 | 333 |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 | 375 |
| 326 | 376 |
| 327 CpuProfile::CpuProfile(const char* title, bool record_samples) | 377 CpuProfile::CpuProfile(const char* title, bool record_samples) |
| 328 : title_(title), | 378 : title_(title), |
| 329 record_samples_(record_samples), | 379 record_samples_(record_samples), |
| 330 start_time_(base::TimeTicks::HighResolutionNow()) { | 380 start_time_(base::TimeTicks::HighResolutionNow()) { |
| 331 } | 381 } |
| 332 | 382 |
| 333 | 383 |
| 334 void CpuProfile::AddPath(base::TimeTicks timestamp, | 384 void CpuProfile::AddPath(base::TimeTicks timestamp, |
| 335 const Vector<CodeEntry*>& path) { | 385 const Vector<CodeEntry*>& path, |
| 336 ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path); | 386 int src_line) { |
| 387 ProfileNode* top_frame_node = top_down_.AddPathFromEnd(path, src_line); | |
| 337 if (record_samples_) { | 388 if (record_samples_) { |
| 338 timestamps_.Add(timestamp); | 389 timestamps_.Add(timestamp); |
| 339 samples_.Add(top_frame_node); | 390 samples_.Add(top_frame_node); |
| 340 } | 391 } |
| 341 } | 392 } |
| 342 | 393 |
| 343 | 394 |
| 344 void CpuProfile::CalculateTotalTicksAndSamplingRate() { | 395 void CpuProfile::CalculateTotalTicksAndSamplingRate() { |
| 345 end_time_ = base::TimeTicks::HighResolutionNow(); | 396 end_time_ = base::TimeTicks::HighResolutionNow(); |
| 346 } | 397 } |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 515 if (profile == finished_profiles_[i]) { | 566 if (profile == finished_profiles_[i]) { |
| 516 finished_profiles_.Remove(i); | 567 finished_profiles_.Remove(i); |
| 517 return; | 568 return; |
| 518 } | 569 } |
| 519 } | 570 } |
| 520 UNREACHABLE(); | 571 UNREACHABLE(); |
| 521 } | 572 } |
| 522 | 573 |
| 523 | 574 |
| 524 void CpuProfilesCollection::AddPathToCurrentProfiles( | 575 void CpuProfilesCollection::AddPathToCurrentProfiles( |
| 525 base::TimeTicks timestamp, const Vector<CodeEntry*>& path) { | 576 base::TimeTicks timestamp, |
| 577 const Vector<CodeEntry*>& path, | |
| 578 int src_line) { | |
| 526 // As starting / stopping profiles is rare relatively to this | 579 // As starting / stopping profiles is rare relatively to this |
| 527 // method, we don't bother minimizing the duration of lock holding, | 580 // method, we don't bother minimizing the duration of lock holding, |
| 528 // e.g. copying contents of the list to a local vector. | 581 // e.g. copying contents of the list to a local vector. |
| 529 current_profiles_semaphore_.Wait(); | 582 current_profiles_semaphore_.Wait(); |
| 530 for (int i = 0; i < current_profiles_.length(); ++i) { | 583 for (int i = 0; i < current_profiles_.length(); ++i) { |
| 531 current_profiles_[i]->AddPath(timestamp, path); | 584 current_profiles_[i]->AddPath(timestamp, path, src_line); |
| 532 } | 585 } |
| 533 current_profiles_semaphore_.Signal(); | 586 current_profiles_semaphore_.Signal(); |
| 534 } | 587 } |
| 535 | 588 |
| 536 | 589 |
| 537 CodeEntry* CpuProfilesCollection::NewCodeEntry( | 590 CodeEntry* CpuProfilesCollection::NewCodeEntry( |
| 538 Logger::LogEventsAndTags tag, | 591 Logger::LogEventsAndTags tag, |
| 539 const char* name, | 592 const char* name, |
| 540 const char* name_prefix, | 593 const char* name_prefix, |
| 541 const char* resource_name, | 594 const char* resource_name, |
| 542 int line_number, | 595 int line_number, |
| 543 int column_number) { | 596 int column_number, |
| 597 JITLineInfoTable* line_info) { | |
| 544 CodeEntry* code_entry = new CodeEntry(tag, | 598 CodeEntry* code_entry = new CodeEntry(tag, |
| 545 name, | 599 name, |
| 546 name_prefix, | 600 name_prefix, |
| 547 resource_name, | 601 resource_name, |
| 548 line_number, | 602 line_number, |
| 549 column_number); | 603 column_number, |
| 604 line_info); | |
| 550 code_entries_.Add(code_entry); | 605 code_entries_.Add(code_entry); |
| 551 return code_entry; | 606 return code_entry; |
| 552 } | 607 } |
| 553 | 608 |
| 554 | 609 |
| 555 const char* const ProfileGenerator::kAnonymousFunctionName = | 610 const char* const ProfileGenerator::kAnonymousFunctionName = |
| 556 "(anonymous function)"; | 611 "(anonymous function)"; |
| 557 const char* const ProfileGenerator::kProgramEntryName = | 612 const char* const ProfileGenerator::kProgramEntryName = |
| 558 "(program)"; | 613 "(program)"; |
| 559 const char* const ProfileGenerator::kIdleEntryName = | 614 const char* const ProfileGenerator::kIdleEntryName = |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 579 } | 634 } |
| 580 | 635 |
| 581 | 636 |
| 582 void ProfileGenerator::RecordTickSample(const TickSample& sample) { | 637 void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
| 583 // Allocate space for stack frames + pc + function + vm-state. | 638 // Allocate space for stack frames + pc + function + vm-state. |
| 584 ScopedVector<CodeEntry*> entries(sample.frames_count + 3); | 639 ScopedVector<CodeEntry*> entries(sample.frames_count + 3); |
| 585 // As actual number of decoded code entries may vary, initialize | 640 // As actual number of decoded code entries may vary, initialize |
| 586 // entries vector with NULL values. | 641 // entries vector with NULL values. |
| 587 CodeEntry** entry = entries.start(); | 642 CodeEntry** entry = entries.start(); |
| 588 memset(entry, 0, entries.length() * sizeof(*entry)); | 643 memset(entry, 0, entries.length() * sizeof(*entry)); |
| 644 | |
| 645 // The ProfileNode knows nothing about all versions of generated code for | |
| 646 // the same JS function. The line number information associated with | |
| 647 // the latest version of generated code is used to find a source line number | |
| 648 // for a JS function. Then, the detected source line is passed to | |
| 649 // ProfileNode to accumulate the samples. | |
| 650 int src_line = v8::CpuProfileNode::kNoLineNumberInfo; | |
| 651 | |
| 589 if (sample.pc != NULL) { | 652 if (sample.pc != NULL) { |
| 590 if (sample.has_external_callback && sample.state == EXTERNAL && | 653 if (sample.has_external_callback && sample.state == EXTERNAL && |
| 591 sample.top_frame_type == StackFrame::EXIT) { | 654 sample.top_frame_type == StackFrame::EXIT) { |
| 592 // Don't use PC when in external callback code, as it can point | 655 // Don't use PC when in external callback code, as it can point |
| 593 // inside callback's code, and we will erroneously report | 656 // inside callback's code, and we will erroneously report |
| 594 // that a callback calls itself. | 657 // that a callback calls itself. |
| 595 *entry++ = code_map_.FindEntry(sample.external_callback); | 658 *entry++ = code_map_.FindEntry(sample.external_callback); |
| 596 } else { | 659 } else { |
| 597 Address start; | 660 Address start; |
| 598 CodeEntry* pc_entry = code_map_.FindEntry(sample.pc, &start); | 661 CodeEntry* pc_entry = code_map_.FindEntry(sample.pc, &start); |
| 599 // If pc is in the function code before it set up stack frame or after the | 662 // If pc is in the function code before it set up stack frame or after the |
| 600 // frame was destroyed SafeStackFrameIterator incorrectly thinks that | 663 // frame was destroyed SafeStackFrameIterator incorrectly thinks that |
| 601 // ebp contains return address of the current function and skips caller's | 664 // ebp contains return address of the current function and skips caller's |
| 602 // frame. Check for this case and just skip such samples. | 665 // frame. Check for this case and just skip such samples. |
| 603 if (pc_entry) { | 666 if (pc_entry) { |
| 604 List<OffsetRange>* ranges = pc_entry->no_frame_ranges(); | 667 List<OffsetRange>* ranges = pc_entry->no_frame_ranges(); |
| 668 Code* code = Code::cast(HeapObject::FromAddress(start)); | |
| 669 int pc_offset = static_cast<int>(sample.pc - code->instruction_start()); | |
| 670 src_line = pc_entry->GetSourceLine(pc_offset); | |
| 605 if (ranges) { | 671 if (ranges) { |
| 606 Code* code = Code::cast(HeapObject::FromAddress(start)); | |
| 607 int pc_offset = static_cast<int>( | |
| 608 sample.pc - code->instruction_start()); | |
| 609 for (int i = 0; i < ranges->length(); i++) { | 672 for (int i = 0; i < ranges->length(); i++) { |
| 610 OffsetRange& range = ranges->at(i); | 673 OffsetRange& range = ranges->at(i); |
| 611 if (range.from <= pc_offset && pc_offset < range.to) { | 674 if (range.from <= pc_offset && pc_offset < range.to) { |
| 612 return; | 675 return; |
| 613 } | 676 } |
| 614 } | 677 } |
| 615 } | 678 } |
| 616 *entry++ = pc_entry; | 679 *entry++ = pc_entry; |
| 617 | 680 |
| 618 if (pc_entry->builtin_id() == Builtins::kFunctionCall || | 681 if (pc_entry->builtin_id() == Builtins::kFunctionCall || |
| 619 pc_entry->builtin_id() == Builtins::kFunctionApply) { | 682 pc_entry->builtin_id() == Builtins::kFunctionApply) { |
| 620 // When current function is FunctionCall or FunctionApply builtin the | 683 // When current function is FunctionCall or FunctionApply builtin the |
| 621 // top frame is either frame of the calling JS function or internal | 684 // top frame is either frame of the calling JS function or internal |
| 622 // frame. In the latter case we know the caller for sure but in the | 685 // frame. In the latter case we know the caller for sure but in the |
| 623 // former case we don't so we simply replace the frame with | 686 // former case we don't so we simply replace the frame with |
| 624 // 'unresolved' entry. | 687 // 'unresolved' entry. |
| 625 if (sample.top_frame_type == StackFrame::JAVA_SCRIPT) { | 688 if (sample.top_frame_type == StackFrame::JAVA_SCRIPT) { |
| 626 *entry++ = unresolved_entry_; | 689 *entry++ = unresolved_entry_; |
| 627 } | 690 } |
| 628 } | 691 } |
| 629 } | 692 } |
| 630 } | 693 } |
| 631 | 694 |
| 695 bool src_line_not_found = src_line == v8::CpuProfileNode::kNoLineNumberInfo; | |
| 696 | |
| 632 for (const Address* stack_pos = sample.stack, | 697 for (const Address* stack_pos = sample.stack, |
| 633 *stack_end = stack_pos + sample.frames_count; | 698 *stack_end = stack_pos + sample.frames_count; |
| 634 stack_pos != stack_end; | 699 stack_pos != stack_end; |
| 635 ++stack_pos) { | 700 ++stack_pos) { |
| 636 *entry++ = code_map_.FindEntry(*stack_pos); | 701 Address start = NULL; |
| 702 *entry = code_map_.FindEntry(*stack_pos, &start); | |
| 703 | |
| 704 // Skip unresolved frames (e.g. internal frame) and get source line of | |
| 705 // the JS caller. | |
| 706 if (src_line_not_found && *entry) { | |
| 707 Code* code = Code::cast(HeapObject::FromAddress(start)); | |
| 708 int pc_offset = | |
| 709 static_cast<int>(*stack_pos - code->instruction_start()); | |
| 710 src_line = (*entry)->GetSourceLine(pc_offset); | |
| 711 if (src_line == v8::CpuProfileNode::kNoLineNumberInfo) { | |
| 712 src_line = (*entry)->line_number(); | |
| 713 } | |
| 714 src_line_not_found = false; | |
| 715 } | |
| 716 | |
| 717 entry++; | |
| 637 } | 718 } |
| 638 } | 719 } |
| 639 | 720 |
| 640 if (FLAG_prof_browser_mode) { | 721 if (FLAG_prof_browser_mode) { |
| 641 bool no_symbolized_entries = true; | 722 bool no_symbolized_entries = true; |
| 642 for (CodeEntry** e = entries.start(); e != entry; ++e) { | 723 for (CodeEntry** e = entries.start(); e != entry; ++e) { |
| 643 if (*e != NULL) { | 724 if (*e != NULL) { |
| 644 no_symbolized_entries = false; | 725 no_symbolized_entries = false; |
| 645 break; | 726 break; |
| 646 } | 727 } |
| 647 } | 728 } |
| 648 // If no frames were symbolized, put the VM state entry in. | 729 // If no frames were symbolized, put the VM state entry in. |
| 649 if (no_symbolized_entries) { | 730 if (no_symbolized_entries) { |
| 650 *entry++ = EntryForVMState(sample.state); | 731 *entry++ = EntryForVMState(sample.state); |
| 651 } | 732 } |
| 652 } | 733 } |
| 653 | 734 |
| 654 profiles_->AddPathToCurrentProfiles(sample.timestamp, entries); | 735 profiles_->AddPathToCurrentProfiles(sample.timestamp, entries, src_line); |
| 655 } | 736 } |
| 656 | 737 |
| 657 | 738 |
| 658 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { | 739 CodeEntry* ProfileGenerator::EntryForVMState(StateTag tag) { |
| 659 switch (tag) { | 740 switch (tag) { |
| 660 case GC: | 741 case GC: |
| 661 return gc_entry_; | 742 return gc_entry_; |
| 662 case JS: | 743 case JS: |
| 663 case COMPILER: | 744 case COMPILER: |
| 664 // DOM events handlers are reported as OTHER / EXTERNAL entries. | 745 // DOM events handlers are reported as OTHER / EXTERNAL entries. |
| 665 // To avoid confusing people, let's put all these entries into | 746 // To avoid confusing people, let's put all these entries into |
| 666 // one bucket. | 747 // one bucket. |
| 667 case OTHER: | 748 case OTHER: |
| 668 case EXTERNAL: | 749 case EXTERNAL: |
| 669 return program_entry_; | 750 return program_entry_; |
| 670 case IDLE: | 751 case IDLE: |
| 671 return idle_entry_; | 752 return idle_entry_; |
| 672 default: return NULL; | 753 default: return NULL; |
| 673 } | 754 } |
| 674 } | 755 } |
| 675 | 756 |
| 676 } } // namespace v8::internal | 757 } } // namespace v8::internal |
| OLD | NEW |