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