| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 || (tag_ == entry->tag_ | 228 || (tag_ == entry->tag_ |
| 229 && shared_id_ == entry->shared_id_ | 229 && shared_id_ == entry->shared_id_ |
| 230 && (shared_id_ != 0 | 230 && (shared_id_ != 0 |
| 231 || (name_prefix_ == entry->name_prefix_ | 231 || (name_prefix_ == entry->name_prefix_ |
| 232 && name_ == entry->name_ | 232 && name_ == entry->name_ |
| 233 && resource_name_ == entry->resource_name_ | 233 && resource_name_ == entry->resource_name_ |
| 234 && line_number_ == entry->line_number_))); | 234 && line_number_ == entry->line_number_))); |
| 235 } | 235 } |
| 236 | 236 |
| 237 | 237 |
| 238 void CodeEntry::SetBuiltinId(Builtins::Name id) { |
| 239 tag_ = Logger::BUILTIN_TAG; |
| 240 builtin_id_ = id; |
| 241 } |
| 242 |
| 243 |
| 238 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { | 244 ProfileNode* ProfileNode::FindChild(CodeEntry* entry) { |
| 239 HashMap::Entry* map_entry = | 245 HashMap::Entry* map_entry = |
| 240 children_.Lookup(entry, CodeEntryHash(entry), false); | 246 children_.Lookup(entry, CodeEntryHash(entry), false); |
| 241 return map_entry != NULL ? | 247 return map_entry != NULL ? |
| 242 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; | 248 reinterpret_cast<ProfileNode*>(map_entry->value) : NULL; |
| 243 } | 249 } |
| 244 | 250 |
| 245 | 251 |
| 246 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { | 252 ProfileNode* ProfileNode::FindOrAddChild(CodeEntry* entry) { |
| 247 HashMap::Entry* map_entry = | 253 HashMap::Entry* map_entry = |
| (...skipping 593 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 841 static_cast<unsigned>(kWallTimeQueryIntervalMs * ticks_per_ms_); | 847 static_cast<unsigned>(kWallTimeQueryIntervalMs * ticks_per_ms_); |
| 842 } | 848 } |
| 843 | 849 |
| 844 | 850 |
| 845 const char* const ProfileGenerator::kAnonymousFunctionName = | 851 const char* const ProfileGenerator::kAnonymousFunctionName = |
| 846 "(anonymous function)"; | 852 "(anonymous function)"; |
| 847 const char* const ProfileGenerator::kProgramEntryName = | 853 const char* const ProfileGenerator::kProgramEntryName = |
| 848 "(program)"; | 854 "(program)"; |
| 849 const char* const ProfileGenerator::kGarbageCollectorEntryName = | 855 const char* const ProfileGenerator::kGarbageCollectorEntryName = |
| 850 "(garbage collector)"; | 856 "(garbage collector)"; |
| 857 const char* const ProfileGenerator::kUnresolvedFunctionName = |
| 858 "(unresolved function)"; |
| 851 | 859 |
| 852 | 860 |
| 853 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) | 861 ProfileGenerator::ProfileGenerator(CpuProfilesCollection* profiles) |
| 854 : profiles_(profiles), | 862 : profiles_(profiles), |
| 855 program_entry_( | 863 program_entry_( |
| 856 profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)), | 864 profiles->NewCodeEntry(Logger::FUNCTION_TAG, kProgramEntryName)), |
| 857 gc_entry_( | 865 gc_entry_( |
| 858 profiles->NewCodeEntry(Logger::BUILTIN_TAG, | 866 profiles->NewCodeEntry(Logger::BUILTIN_TAG, |
| 859 kGarbageCollectorEntryName)) { | 867 kGarbageCollectorEntryName)), |
| 868 unresolved_entry_( |
| 869 profiles->NewCodeEntry(Logger::FUNCTION_TAG, |
| 870 kUnresolvedFunctionName)) { |
| 860 } | 871 } |
| 861 | 872 |
| 862 | 873 |
| 863 void ProfileGenerator::RecordTickSample(const TickSample& sample) { | 874 void ProfileGenerator::RecordTickSample(const TickSample& sample) { |
| 864 // Allocate space for stack frames + pc + function + vm-state. | 875 // Allocate space for stack frames + pc + function + vm-state. |
| 865 ScopedVector<CodeEntry*> entries(sample.frames_count + 3); | 876 ScopedVector<CodeEntry*> entries(sample.frames_count + 3); |
| 866 // As actual number of decoded code entries may vary, initialize | 877 // As actual number of decoded code entries may vary, initialize |
| 867 // entries vector with NULL values. | 878 // entries vector with NULL values. |
| 868 CodeEntry** entry = entries.start(); | 879 CodeEntry** entry = entries.start(); |
| 869 memset(entry, 0, entries.length() * sizeof(*entry)); | 880 memset(entry, 0, entries.length() * sizeof(*entry)); |
| 870 if (sample.pc != NULL) { | 881 if (sample.pc != NULL) { |
| 871 Address start; | |
| 872 CodeEntry* pc_entry = code_map_.FindEntry(sample.pc, &start); | |
| 873 // If pc is in the function code before it set up stack frame or after the | |
| 874 // frame was destroyed SafeStackFrameIterator incorrectly thinks that | |
| 875 // ebp contains return address of the current function and skips caller's | |
| 876 // frame. Check for this case and just skip such samples. | |
| 877 if (pc_entry) { | |
| 878 List<OffsetRange>* ranges = pc_entry->no_frame_ranges(); | |
| 879 if (ranges) { | |
| 880 Code* code = Code::cast(HeapObject::FromAddress(start)); | |
| 881 int pc_offset = static_cast<int>(sample.pc - code->instruction_start()); | |
| 882 for (int i = 0; i < ranges->length(); i++) { | |
| 883 OffsetRange& range = ranges->at(i); | |
| 884 if (range.from <= pc_offset && pc_offset < range.to) { | |
| 885 return; | |
| 886 } | |
| 887 } | |
| 888 } | |
| 889 } | |
| 890 *entry++ = pc_entry; | |
| 891 | |
| 892 if (sample.has_external_callback) { | 882 if (sample.has_external_callback) { |
| 893 // Don't use PC when in external callback code, as it can point | 883 // Don't use PC when in external callback code, as it can point |
| 894 // inside callback's code, and we will erroneously report | 884 // inside callback's code, and we will erroneously report |
| 895 // that a callback calls itself. | 885 // that a callback calls itself. |
| 896 *(entries.start()) = NULL; | |
| 897 *entry++ = code_map_.FindEntry(sample.external_callback); | 886 *entry++ = code_map_.FindEntry(sample.external_callback); |
| 887 } else { |
| 888 Address start; |
| 889 CodeEntry* pc_entry = code_map_.FindEntry(sample.pc, &start); |
| 890 // If pc is in the function code before it set up stack frame or after the |
| 891 // frame was destroyed SafeStackFrameIterator incorrectly thinks that |
| 892 // ebp contains return address of the current function and skips caller's |
| 893 // frame. Check for this case and just skip such samples. |
| 894 if (pc_entry) { |
| 895 List<OffsetRange>* ranges = pc_entry->no_frame_ranges(); |
| 896 if (ranges) { |
| 897 Code* code = Code::cast(HeapObject::FromAddress(start)); |
| 898 int pc_offset = static_cast<int>( |
| 899 sample.pc - code->instruction_start()); |
| 900 for (int i = 0; i < ranges->length(); i++) { |
| 901 OffsetRange& range = ranges->at(i); |
| 902 if (range.from <= pc_offset && pc_offset < range.to) { |
| 903 return; |
| 904 } |
| 905 } |
| 906 } |
| 907 *entry++ = pc_entry; |
| 908 |
| 909 if (pc_entry->builtin_id() == Builtins::kFunctionCall) { |
| 910 // When current function is FunctionCall builtin tos is sometimes |
| 911 // address of the function that invoked it but sometimes it's one |
| 912 // of the arguments. We simply replace the frame with 'unknown' entry. |
| 913 *entry++ = unresolved_entry_; |
| 914 } |
| 915 } |
| 898 } | 916 } |
| 899 | 917 |
| 900 for (const Address* stack_pos = sample.stack, | 918 for (const Address* stack_pos = sample.stack, |
| 901 *stack_end = stack_pos + sample.frames_count; | 919 *stack_end = stack_pos + sample.frames_count; |
| 902 stack_pos != stack_end; | 920 stack_pos != stack_end; |
| 903 ++stack_pos) { | 921 ++stack_pos) { |
| 904 *entry++ = code_map_.FindEntry(*stack_pos); | 922 *entry++ = code_map_.FindEntry(*stack_pos); |
| 905 } | 923 } |
| 906 } | 924 } |
| 907 | 925 |
| 908 if (FLAG_prof_browser_mode) { | 926 if (FLAG_prof_browser_mode) { |
| 909 bool no_symbolized_entries = true; | 927 bool no_symbolized_entries = true; |
| 910 for (CodeEntry** e = entries.start(); e != entry; ++e) { | 928 for (CodeEntry** e = entries.start(); e != entry; ++e) { |
| 911 if (*e != NULL) { | 929 if (*e != NULL) { |
| 912 no_symbolized_entries = false; | 930 no_symbolized_entries = false; |
| 913 break; | 931 break; |
| 914 } | 932 } |
| 915 } | 933 } |
| 916 // If no frames were symbolized, put the VM state entry in. | 934 // If no frames were symbolized, put the VM state entry in. |
| 917 if (no_symbolized_entries) { | 935 if (no_symbolized_entries) { |
| 918 *entry++ = EntryForVMState(sample.state); | 936 *entry++ = EntryForVMState(sample.state); |
| 919 } | 937 } |
| 920 } | 938 } |
| 921 | 939 |
| 922 profiles_->AddPathToCurrentProfiles(entries); | 940 profiles_->AddPathToCurrentProfiles(entries); |
| 923 } | 941 } |
| 924 | 942 |
| 925 | 943 |
| 926 } } // namespace v8::internal | 944 } } // namespace v8::internal |
| OLD | NEW |