| 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 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 const char* const CodeEntry::kEmptyBailoutReason = ""; | 162 const char* const CodeEntry::kEmptyBailoutReason = ""; |
| 163 const char* const CodeEntry::kNoDeoptReason = ""; | 163 const char* const CodeEntry::kNoDeoptReason = ""; |
| 164 | 164 |
| 165 | 165 |
| 166 CodeEntry::~CodeEntry() { | 166 CodeEntry::~CodeEntry() { |
| 167 delete no_frame_ranges_; | 167 delete no_frame_ranges_; |
| 168 delete line_info_; | 168 delete line_info_; |
| 169 } | 169 } |
| 170 | 170 |
| 171 | 171 |
| 172 uint32_t CodeEntry::GetCallUid() const { | 172 uint32_t CodeEntry::GetHash() const { |
| 173 uint32_t hash = ComputeIntegerHash(tag(), v8::internal::kZeroHashSeed); | 173 uint32_t hash = ComputeIntegerHash(tag(), v8::internal::kZeroHashSeed); |
| 174 if (shared_id_ != 0) { | 174 if (script_id_ != v8::UnboundScript::kNoScriptId) { |
| 175 hash ^= ComputeIntegerHash(static_cast<uint32_t>(shared_id_), | 175 hash ^= ComputeIntegerHash(static_cast<uint32_t>(script_id_), |
| 176 v8::internal::kZeroHashSeed); |
| 177 hash ^= ComputeIntegerHash(static_cast<uint32_t>(position_), |
| 176 v8::internal::kZeroHashSeed); | 178 v8::internal::kZeroHashSeed); |
| 177 } else { | 179 } else { |
| 178 hash ^= ComputeIntegerHash( | 180 hash ^= ComputeIntegerHash( |
| 179 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)), | 181 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_prefix_)), |
| 180 v8::internal::kZeroHashSeed); | 182 v8::internal::kZeroHashSeed); |
| 181 hash ^= ComputeIntegerHash( | 183 hash ^= ComputeIntegerHash( |
| 182 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)), | 184 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(name_)), |
| 183 v8::internal::kZeroHashSeed); | 185 v8::internal::kZeroHashSeed); |
| 184 hash ^= ComputeIntegerHash( | 186 hash ^= ComputeIntegerHash( |
| 185 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)), | 187 static_cast<uint32_t>(reinterpret_cast<uintptr_t>(resource_name_)), |
| 186 v8::internal::kZeroHashSeed); | 188 v8::internal::kZeroHashSeed); |
| 187 hash ^= ComputeIntegerHash(line_number_, v8::internal::kZeroHashSeed); | 189 hash ^= ComputeIntegerHash(line_number_, v8::internal::kZeroHashSeed); |
| 188 } | 190 } |
| 189 return hash; | 191 return hash; |
| 190 } | 192 } |
| 191 | 193 |
| 192 | 194 |
| 193 bool CodeEntry::IsSameAs(CodeEntry* entry) const { | 195 bool CodeEntry::IsSameFunctionAs(CodeEntry* entry) const { |
| 194 return this == entry || | 196 if (this == entry) return true; |
| 195 (tag() == entry->tag() && shared_id_ == entry->shared_id_ && | 197 if (script_id_ != v8::UnboundScript::kNoScriptId) { |
| 196 (shared_id_ != 0 || | 198 return script_id_ == entry->script_id_ && position_ == entry->position_; |
| 197 (name_prefix_ == entry->name_prefix_ && name_ == entry->name_ && | 199 } |
| 198 resource_name_ == entry->resource_name_ && | 200 return name_prefix_ == entry->name_prefix_ && name_ == entry->name_ && |
| 199 line_number_ == entry->line_number_))); | 201 resource_name_ == entry->resource_name_ && |
| 202 line_number_ == entry->line_number_; |
| 200 } | 203 } |
| 201 | 204 |
| 202 | 205 |
| 203 void CodeEntry::SetBuiltinId(Builtins::Name id) { | 206 void CodeEntry::SetBuiltinId(Builtins::Name id) { |
| 204 bit_field_ = TagField::update(bit_field_, Logger::BUILTIN_TAG); | 207 bit_field_ = TagField::update(bit_field_, Logger::BUILTIN_TAG); |
| 205 bit_field_ = BuiltinIdField::update(bit_field_, id); | 208 bit_field_ = BuiltinIdField::update(bit_field_, id); |
| 206 } | 209 } |
| 207 | 210 |
| 208 | 211 |
| 209 int CodeEntry::GetSourceLine(int pc_offset) const { | 212 int CodeEntry::GetSourceLine(int pc_offset) const { |
| 210 if (line_info_ && !line_info_->empty()) { | 213 if (line_info_ && !line_info_->empty()) { |
| 211 return line_info_->GetSourceLineNumber(pc_offset); | 214 return line_info_->GetSourceLineNumber(pc_offset); |
| 212 } | 215 } |
| 213 return v8::CpuProfileNode::kNoLineNumberInfo; | 216 return v8::CpuProfileNode::kNoLineNumberInfo; |
| 214 } | 217 } |
| 215 | 218 |
| 216 | 219 |
| 220 void CodeEntry::FillFunctionInfo(SharedFunctionInfo* shared) { |
| 221 if (!shared->script()->IsScript()) return; |
| 222 Script* script = Script::cast(shared->script()); |
| 223 set_script_id(script->id()->value()); |
| 224 set_position(shared->start_position()); |
| 225 set_bailout_reason(GetBailoutReason(shared->disable_optimization_reason())); |
| 226 } |
| 227 |
| 228 |
| 217 void ProfileNode::CollectDeoptInfo(CodeEntry* entry) { | 229 void ProfileNode::CollectDeoptInfo(CodeEntry* entry) { |
| 218 deopt_infos_.Add(DeoptInfo(entry->deopt_reason(), entry->deopt_location())); | 230 deopt_infos_.Add(DeoptInfo(entry->deopt_reason(), entry->deopt_location())); |
| 219 entry->clear_deopt_info(); | 231 entry->clear_deopt_info(); |
| 220 } | 232 } |
| 221 | 233 |
| 222 | 234 |
| 223 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { | 235 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { |
| 224 HashMap::Entry* map_entry = | 236 HashMap::Entry* map_entry = |
| 225 children_.Lookup(entry, CodeEntryHash(entry), false); | 237 children_.Lookup(entry, CodeEntryHash(entry), false); |
| 226 return map_entry != NULL ? | 238 return map_entry != NULL ? |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 309 delete node; | 321 delete node; |
| 310 } | 322 } |
| 311 | 323 |
| 312 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } | 324 void AfterChildTraversed(ProfileNode*, ProfileNode*) { } |
| 313 }; | 325 }; |
| 314 | 326 |
| 315 | 327 |
| 316 ProfileTree::ProfileTree() | 328 ProfileTree::ProfileTree() |
| 317 : root_entry_(Logger::FUNCTION_TAG, "(root)"), | 329 : root_entry_(Logger::FUNCTION_TAG, "(root)"), |
| 318 next_node_id_(1), | 330 next_node_id_(1), |
| 319 root_(new ProfileNode(this, &root_entry_)) { | 331 root_(new ProfileNode(this, &root_entry_)), |
| 320 } | 332 next_function_id_(1), |
| 333 function_ids_(ProfileNode::CodeEntriesMatch) {} |
| 321 | 334 |
| 322 | 335 |
| 323 ProfileTree::~ProfileTree() { | 336 ProfileTree::~ProfileTree() { |
| 324 DeleteNodesCallback cb; | 337 DeleteNodesCallback cb; |
| 325 TraverseDepthFirst(&cb); | 338 TraverseDepthFirst(&cb); |
| 326 } | 339 } |
| 327 | 340 |
| 328 | 341 |
| 342 unsigned ProfileTree::GetFunctionId(const ProfileNode* node) { |
| 343 CodeEntry* code_entry = node->entry(); |
| 344 HashMap::Entry* entry = |
| 345 function_ids_.Lookup(code_entry, code_entry->GetHash(), true); |
| 346 if (!entry->value) { |
| 347 entry->value = reinterpret_cast<void*>(next_function_id_++); |
| 348 } |
| 349 return static_cast<unsigned>(reinterpret_cast<uintptr_t>(entry->value)); |
| 350 } |
| 351 |
| 352 |
| 329 ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path, | 353 ProfileNode* ProfileTree::AddPathFromEnd(const Vector<CodeEntry*>& path, |
| 330 int src_line) { | 354 int src_line) { |
| 331 ProfileNode* node = root_; | 355 ProfileNode* node = root_; |
| 332 CodeEntry* last_entry = NULL; | 356 CodeEntry* last_entry = NULL; |
| 333 for (CodeEntry** entry = path.start() + path.length() - 1; | 357 for (CodeEntry** entry = path.start() + path.length() - 1; |
| 334 entry != path.start() - 1; | 358 entry != path.start() - 1; |
| 335 --entry) { | 359 --entry) { |
| 336 if (*entry != NULL) { | 360 if (*entry != NULL) { |
| 337 node = node->FindOrAddChild(*entry); | 361 node = node->FindOrAddChild(*entry); |
| 338 last_entry = *entry; | 362 last_entry = *entry; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 420 end_time_ = base::TimeTicks::HighResolutionNow(); | 444 end_time_ = base::TimeTicks::HighResolutionNow(); |
| 421 } | 445 } |
| 422 | 446 |
| 423 | 447 |
| 424 void CpuProfile::Print() { | 448 void CpuProfile::Print() { |
| 425 base::OS::Print("[Top down]:\n"); | 449 base::OS::Print("[Top down]:\n"); |
| 426 top_down_.Print(); | 450 top_down_.Print(); |
| 427 } | 451 } |
| 428 | 452 |
| 429 | 453 |
| 430 CodeEntry* const CodeMap::kSharedFunctionCodeEntry = NULL; | |
| 431 const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL; | 454 const CodeMap::CodeTreeConfig::Key CodeMap::CodeTreeConfig::kNoKey = NULL; |
| 432 | 455 |
| 433 | 456 |
| 434 void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) { | 457 void CodeMap::AddCode(Address addr, CodeEntry* entry, unsigned size) { |
| 435 DeleteAllCoveredCode(addr, addr + size); | 458 DeleteAllCoveredCode(addr, addr + size); |
| 436 CodeTree::Locator locator; | 459 CodeTree::Locator locator; |
| 437 tree_.Insert(addr, &locator); | 460 tree_.Insert(addr, &locator); |
| 438 locator.set_value(CodeEntryInfo(entry, size)); | 461 locator.set_value(CodeEntryInfo(entry, size)); |
| 439 } | 462 } |
| 440 | 463 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 462 if (start) { | 485 if (start) { |
| 463 *start = locator.key(); | 486 *start = locator.key(); |
| 464 } | 487 } |
| 465 return entry.entry; | 488 return entry.entry; |
| 466 } | 489 } |
| 467 } | 490 } |
| 468 return NULL; | 491 return NULL; |
| 469 } | 492 } |
| 470 | 493 |
| 471 | 494 |
| 472 int CodeMap::GetSharedId(Address addr) { | |
| 473 CodeTree::Locator locator; | |
| 474 // For shared function entries, 'size' field is used to store their IDs. | |
| 475 if (tree_.Find(addr, &locator)) { | |
| 476 const CodeEntryInfo& entry = locator.value(); | |
| 477 DCHECK(entry.entry == kSharedFunctionCodeEntry); | |
| 478 return entry.size; | |
| 479 } else { | |
| 480 tree_.Insert(addr, &locator); | |
| 481 int id = next_shared_id_++; | |
| 482 locator.set_value(CodeEntryInfo(kSharedFunctionCodeEntry, id)); | |
| 483 return id; | |
| 484 } | |
| 485 } | |
| 486 | |
| 487 | |
| 488 void CodeMap::MoveCode(Address from, Address to) { | 495 void CodeMap::MoveCode(Address from, Address to) { |
| 489 if (from == to) return; | 496 if (from == to) return; |
| 490 CodeTree::Locator locator; | 497 CodeTree::Locator locator; |
| 491 if (!tree_.Find(from, &locator)) return; | 498 if (!tree_.Find(from, &locator)) return; |
| 492 CodeEntryInfo entry = locator.value(); | 499 CodeEntryInfo entry = locator.value(); |
| 493 tree_.Remove(from); | 500 tree_.Remove(from); |
| 494 AddCode(to, entry.entry, entry.size); | 501 AddCode(to, entry.entry, entry.size); |
| 495 } | 502 } |
| 496 | 503 |
| 497 | 504 |
| 498 void CodeMap::CodeTreePrinter::Call( | 505 void CodeMap::CodeTreePrinter::Call( |
| 499 const Address& key, const CodeMap::CodeEntryInfo& value) { | 506 const Address& key, const CodeMap::CodeEntryInfo& value) { |
| 500 // For shared function entries, 'size' field is used to store their IDs. | 507 base::OS::Print("%p %5d %s\n", key, value.size, value.entry->name()); |
| 501 if (value.entry == kSharedFunctionCodeEntry) { | |
| 502 base::OS::Print("%p SharedFunctionInfo %d\n", key, value.size); | |
| 503 } else { | |
| 504 base::OS::Print("%p %5d %s\n", key, value.size, value.entry->name()); | |
| 505 } | |
| 506 } | 508 } |
| 507 | 509 |
| 508 | 510 |
| 509 void CodeMap::Print() { | 511 void CodeMap::Print() { |
| 510 CodeTreePrinter printer; | 512 CodeTreePrinter printer; |
| 511 tree_.ForEach(&printer); | 513 tree_.ForEach(&printer); |
| 512 } | 514 } |
| 513 | 515 |
| 514 | 516 |
| 515 CpuProfilesCollection::CpuProfilesCollection(Heap* heap) | 517 CpuProfilesCollection::CpuProfilesCollection(Heap* heap) |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 case OTHER: | 764 case OTHER: |
| 763 case EXTERNAL: | 765 case EXTERNAL: |
| 764 return program_entry_; | 766 return program_entry_; |
| 765 case IDLE: | 767 case IDLE: |
| 766 return idle_entry_; | 768 return idle_entry_; |
| 767 default: return NULL; | 769 default: return NULL; |
| 768 } | 770 } |
| 769 } | 771 } |
| 770 | 772 |
| 771 } } // namespace v8::internal | 773 } } // namespace v8::internal |
| OLD | NEW |