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