Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/profiler/heap-snapshot-generator.h" | 5 #include "src/profiler/heap-snapshot-generator.h" |
| 6 | 6 |
| 7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
| 8 #include "src/conversions.h" | 8 #include "src/conversions.h" |
| 9 #include "src/debug/debug.h" | 9 #include "src/debug/debug.h" |
| 10 #include "src/objects-body-descriptors.h" | 10 #include "src/objects-body-descriptors.h" |
| (...skipping 970 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 981 obj != NULL; | 981 obj != NULL; |
| 982 obj = iterator->next()) { | 982 obj = iterator->next()) { |
| 983 objects_count++; | 983 objects_count++; |
| 984 } | 984 } |
| 985 return objects_count; | 985 return objects_count; |
| 986 } | 986 } |
| 987 | 987 |
| 988 | 988 |
| 989 class IndexedReferencesExtractor : public ObjectVisitor { | 989 class IndexedReferencesExtractor : public ObjectVisitor { |
| 990 public: | 990 public: |
| 991 IndexedReferencesExtractor(V8HeapExplorer* generator, | 991 IndexedReferencesExtractor(V8HeapExplorer* generator, HeapObject* parent_obj, |
| 992 HeapObject* parent_obj, | |
| 993 int parent) | 992 int parent) |
| 994 : generator_(generator), | 993 : generator_(generator), |
| 995 parent_obj_(parent_obj), | 994 parent_obj_(parent_obj), |
| 995 real_end_(HeapObject::RawField(parent_obj_, parent_obj_->Size())), | |
| 996 parent_(parent), | 996 parent_(parent), |
| 997 next_index_(0) { | 997 next_index_(0) {} |
| 998 } | |
| 999 void VisitCodeEntry(Address entry_address) override { | 998 void VisitCodeEntry(Address entry_address) override { |
| 1000 Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address)); | 999 Code* code = Code::cast(Code::GetObjectFromEntryAddress(entry_address)); |
| 1001 generator_->SetInternalReference(parent_obj_, parent_, "code", code); | 1000 generator_->SetInternalReference(parent_obj_, parent_, "code", code); |
| 1002 generator_->TagCodeObject(code); | 1001 generator_->TagCodeObject(code); |
| 1003 } | 1002 } |
| 1004 void VisitPointers(Object** start, Object** end) override { | 1003 void VisitPointers(Object** start, Object** end) override { |
| 1005 for (Object** p = start; p < end; p++) { | 1004 for (Object** p = start; p < end; p++) { |
| 1005 intptr_t index = | |
| 1006 static_cast<intptr_t>(p - HeapObject::RawField(parent_obj_, 0)); | |
| 1006 ++next_index_; | 1007 ++next_index_; |
| 1007 if (CheckVisitedAndUnmark(p)) continue; | 1008 if (p >= HeapObject::RawField(parent_obj_, 0) && p < real_end_ && |
|
Igor Sheludko
2015/11/27 10:16:39
I think it would be cleaner to have both object_st
| |
| 1009 generator_->marks_[index]) { | |
| 1010 generator_->marks_[index] = false; | |
| 1011 continue; | |
| 1012 } | |
| 1008 generator_->SetHiddenReference(parent_obj_, parent_, next_index_, *p); | 1013 generator_->SetHiddenReference(parent_obj_, parent_, next_index_, *p); |
| 1009 } | 1014 } |
| 1010 } | 1015 } |
| 1011 static void MarkVisitedField(HeapObject* obj, int offset) { | |
| 1012 if (offset < 0) return; | |
| 1013 Address field = obj->address() + offset; | |
| 1014 DCHECK(Memory::Object_at(field)->IsHeapObject()); | |
| 1015 intptr_t p = reinterpret_cast<intptr_t>(Memory::Object_at(field)); | |
| 1016 DCHECK(!IsMarked(p)); | |
| 1017 intptr_t p_tagged = p | kTag; | |
| 1018 Memory::Object_at(field) = reinterpret_cast<Object*>(p_tagged); | |
| 1019 } | |
| 1020 | 1016 |
| 1021 private: | 1017 private: |
| 1022 bool CheckVisitedAndUnmark(Object** field) { | |
| 1023 intptr_t p = reinterpret_cast<intptr_t>(*field); | |
| 1024 if (IsMarked(p)) { | |
| 1025 intptr_t p_untagged = (p & ~kTaggingMask) | kHeapObjectTag; | |
| 1026 *field = reinterpret_cast<Object*>(p_untagged); | |
| 1027 DCHECK((*field)->IsHeapObject()); | |
| 1028 return true; | |
| 1029 } | |
| 1030 return false; | |
| 1031 } | |
| 1032 | |
| 1033 static const intptr_t kTaggingMask = 3; | |
| 1034 static const intptr_t kTag = 3; | |
| 1035 | |
| 1036 static bool IsMarked(intptr_t p) { return (p & kTaggingMask) == kTag; } | |
| 1037 | |
| 1038 V8HeapExplorer* generator_; | 1018 V8HeapExplorer* generator_; |
| 1039 HeapObject* parent_obj_; | 1019 HeapObject* parent_obj_; |
| 1020 Object** real_end_; | |
| 1040 int parent_; | 1021 int parent_; |
| 1041 int next_index_; | 1022 int next_index_; |
| 1042 }; | 1023 }; |
| 1043 | 1024 |
| 1044 | 1025 |
| 1045 bool V8HeapExplorer::ExtractReferencesPass1(int entry, HeapObject* obj) { | 1026 bool V8HeapExplorer::ExtractReferencesPass1(int entry, HeapObject* obj) { |
| 1046 if (obj->IsFixedArray()) return false; // FixedArrays are processed on pass 2 | 1027 if (obj->IsFixedArray()) return false; // FixedArrays are processed on pass 2 |
| 1047 | 1028 |
| 1048 if (obj->IsJSGlobalProxy()) { | 1029 if (obj->IsJSGlobalProxy()) { |
| 1049 ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj)); | 1030 ExtractJSGlobalProxyReferences(entry, JSGlobalProxy::cast(obj)); |
| (...skipping 814 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1864 bool V8HeapExplorer::IterateAndExtractSinglePass() { | 1845 bool V8HeapExplorer::IterateAndExtractSinglePass() { |
| 1865 // Now iterate the whole heap. | 1846 // Now iterate the whole heap. |
| 1866 bool interrupted = false; | 1847 bool interrupted = false; |
| 1867 HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable); | 1848 HeapIterator iterator(heap_, HeapIterator::kFilterUnreachable); |
| 1868 // Heap iteration with filtering must be finished in any case. | 1849 // Heap iteration with filtering must be finished in any case. |
| 1869 for (HeapObject* obj = iterator.next(); | 1850 for (HeapObject* obj = iterator.next(); |
| 1870 obj != NULL; | 1851 obj != NULL; |
| 1871 obj = iterator.next(), progress_->ProgressStep()) { | 1852 obj = iterator.next(), progress_->ProgressStep()) { |
| 1872 if (interrupted) continue; | 1853 if (interrupted) continue; |
| 1873 | 1854 |
| 1855 int max_pointer = obj->Size() / kPointerSize; | |
| 1856 if (max_pointer > marks_.size()) { | |
| 1857 // Clear the current bits. | |
| 1858 std::vector<bool>().swap(marks_); | |
| 1859 // Reallocate to right size. | |
| 1860 marks_.resize(max_pointer, false); | |
| 1861 } | |
| 1862 | |
| 1874 HeapEntry* heap_entry = GetEntry(obj); | 1863 HeapEntry* heap_entry = GetEntry(obj); |
| 1875 int entry = heap_entry->index(); | 1864 int entry = heap_entry->index(); |
| 1876 if ((this->*extractor)(entry, obj)) { | 1865 if ((this->*extractor)(entry, obj)) { |
| 1877 SetInternalReference(obj, entry, | 1866 SetInternalReference(obj, entry, |
| 1878 "map", obj->map(), HeapObject::kMapOffset); | 1867 "map", obj->map(), HeapObject::kMapOffset); |
| 1879 // Extract unvisited fields as hidden references and restore tags | 1868 // Extract unvisited fields as hidden references and restore tags |
| 1880 // of visited fields. | 1869 // of visited fields. |
| 1881 IndexedReferencesExtractor refs_extractor(this, obj, entry); | 1870 IndexedReferencesExtractor refs_extractor(this, obj, entry); |
| 1882 obj->Iterate(&refs_extractor); | 1871 obj->Iterate(&refs_extractor); |
| 1883 } | 1872 } |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1908 String* reference_name, | 1897 String* reference_name, |
| 1909 Object* child_obj, | 1898 Object* child_obj, |
| 1910 int field_offset) { | 1899 int field_offset) { |
| 1911 DCHECK(parent_entry == GetEntry(parent_obj)->index()); | 1900 DCHECK(parent_entry == GetEntry(parent_obj)->index()); |
| 1912 HeapEntry* child_entry = GetEntry(child_obj); | 1901 HeapEntry* child_entry = GetEntry(child_obj); |
| 1913 if (child_entry != NULL) { | 1902 if (child_entry != NULL) { |
| 1914 filler_->SetNamedReference(HeapGraphEdge::kContextVariable, | 1903 filler_->SetNamedReference(HeapGraphEdge::kContextVariable, |
| 1915 parent_entry, | 1904 parent_entry, |
| 1916 names_->GetName(reference_name), | 1905 names_->GetName(reference_name), |
| 1917 child_entry); | 1906 child_entry); |
| 1918 IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); | 1907 MarkVisitedField(parent_obj, field_offset); |
| 1919 } | 1908 } |
| 1920 } | 1909 } |
| 1921 | 1910 |
| 1922 | 1911 |
| 1912 void V8HeapExplorer::MarkVisitedField(HeapObject* obj, int offset) { | |
| 1913 if (offset < 0) return; | |
| 1914 int index = offset / kPointerSize; | |
| 1915 DCHECK(!marks_[index]); | |
| 1916 marks_[index] = true; | |
| 1917 } | |
| 1918 | |
| 1919 | |
| 1923 void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj, | 1920 void V8HeapExplorer::SetNativeBindReference(HeapObject* parent_obj, |
| 1924 int parent_entry, | 1921 int parent_entry, |
| 1925 const char* reference_name, | 1922 const char* reference_name, |
| 1926 Object* child_obj) { | 1923 Object* child_obj) { |
| 1927 DCHECK(parent_entry == GetEntry(parent_obj)->index()); | 1924 DCHECK(parent_entry == GetEntry(parent_obj)->index()); |
| 1928 HeapEntry* child_entry = GetEntry(child_obj); | 1925 HeapEntry* child_entry = GetEntry(child_obj); |
| 1929 if (child_entry != NULL) { | 1926 if (child_entry != NULL) { |
| 1930 filler_->SetNamedReference(HeapGraphEdge::kShortcut, | 1927 filler_->SetNamedReference(HeapGraphEdge::kShortcut, |
| 1931 parent_entry, | 1928 parent_entry, |
| 1932 reference_name, | 1929 reference_name, |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 1957 int field_offset) { | 1954 int field_offset) { |
| 1958 DCHECK(parent_entry == GetEntry(parent_obj)->index()); | 1955 DCHECK(parent_entry == GetEntry(parent_obj)->index()); |
| 1959 HeapEntry* child_entry = GetEntry(child_obj); | 1956 HeapEntry* child_entry = GetEntry(child_obj); |
| 1960 if (child_entry == NULL) return; | 1957 if (child_entry == NULL) return; |
| 1961 if (IsEssentialObject(child_obj)) { | 1958 if (IsEssentialObject(child_obj)) { |
| 1962 filler_->SetNamedReference(HeapGraphEdge::kInternal, | 1959 filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| 1963 parent_entry, | 1960 parent_entry, |
| 1964 reference_name, | 1961 reference_name, |
| 1965 child_entry); | 1962 child_entry); |
| 1966 } | 1963 } |
| 1967 IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); | 1964 MarkVisitedField(parent_obj, field_offset); |
| 1968 } | 1965 } |
| 1969 | 1966 |
| 1970 | 1967 |
| 1971 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, | 1968 void V8HeapExplorer::SetInternalReference(HeapObject* parent_obj, |
| 1972 int parent_entry, | 1969 int parent_entry, |
| 1973 int index, | 1970 int index, |
| 1974 Object* child_obj, | 1971 Object* child_obj, |
| 1975 int field_offset) { | 1972 int field_offset) { |
| 1976 DCHECK(parent_entry == GetEntry(parent_obj)->index()); | 1973 DCHECK(parent_entry == GetEntry(parent_obj)->index()); |
| 1977 HeapEntry* child_entry = GetEntry(child_obj); | 1974 HeapEntry* child_entry = GetEntry(child_obj); |
| 1978 if (child_entry == NULL) return; | 1975 if (child_entry == NULL) return; |
| 1979 if (IsEssentialObject(child_obj)) { | 1976 if (IsEssentialObject(child_obj)) { |
| 1980 filler_->SetNamedReference(HeapGraphEdge::kInternal, | 1977 filler_->SetNamedReference(HeapGraphEdge::kInternal, |
| 1981 parent_entry, | 1978 parent_entry, |
| 1982 names_->GetName(index), | 1979 names_->GetName(index), |
| 1983 child_entry); | 1980 child_entry); |
| 1984 } | 1981 } |
| 1985 IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); | 1982 MarkVisitedField(parent_obj, field_offset); |
| 1986 } | 1983 } |
| 1987 | 1984 |
| 1988 | 1985 |
| 1989 void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, | 1986 void V8HeapExplorer::SetHiddenReference(HeapObject* parent_obj, |
| 1990 int parent_entry, | 1987 int parent_entry, |
| 1991 int index, | 1988 int index, |
| 1992 Object* child_obj) { | 1989 Object* child_obj) { |
| 1993 DCHECK(parent_entry == GetEntry(parent_obj)->index()); | 1990 DCHECK(parent_entry == GetEntry(parent_obj)->index()); |
| 1994 HeapEntry* child_entry = GetEntry(child_obj); | 1991 HeapEntry* child_entry = GetEntry(child_obj); |
| 1995 if (child_entry != NULL && IsEssentialObject(child_obj)) { | 1992 if (child_entry != NULL && IsEssentialObject(child_obj)) { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 2008 int field_offset) { | 2005 int field_offset) { |
| 2009 DCHECK(parent_entry == GetEntry(parent_obj)->index()); | 2006 DCHECK(parent_entry == GetEntry(parent_obj)->index()); |
| 2010 HeapEntry* child_entry = GetEntry(child_obj); | 2007 HeapEntry* child_entry = GetEntry(child_obj); |
| 2011 if (child_entry == NULL) return; | 2008 if (child_entry == NULL) return; |
| 2012 if (IsEssentialObject(child_obj)) { | 2009 if (IsEssentialObject(child_obj)) { |
| 2013 filler_->SetNamedReference(HeapGraphEdge::kWeak, | 2010 filler_->SetNamedReference(HeapGraphEdge::kWeak, |
| 2014 parent_entry, | 2011 parent_entry, |
| 2015 reference_name, | 2012 reference_name, |
| 2016 child_entry); | 2013 child_entry); |
| 2017 } | 2014 } |
| 2018 IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); | 2015 MarkVisitedField(parent_obj, field_offset); |
| 2019 } | 2016 } |
| 2020 | 2017 |
| 2021 | 2018 |
| 2022 void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, | 2019 void V8HeapExplorer::SetWeakReference(HeapObject* parent_obj, |
| 2023 int parent_entry, | 2020 int parent_entry, |
| 2024 int index, | 2021 int index, |
| 2025 Object* child_obj, | 2022 Object* child_obj, |
| 2026 int field_offset) { | 2023 int field_offset) { |
| 2027 DCHECK(parent_entry == GetEntry(parent_obj)->index()); | 2024 DCHECK(parent_entry == GetEntry(parent_obj)->index()); |
| 2028 HeapEntry* child_entry = GetEntry(child_obj); | 2025 HeapEntry* child_entry = GetEntry(child_obj); |
| 2029 if (child_entry == NULL) return; | 2026 if (child_entry == NULL) return; |
| 2030 if (IsEssentialObject(child_obj)) { | 2027 if (IsEssentialObject(child_obj)) { |
| 2031 filler_->SetNamedReference(HeapGraphEdge::kWeak, | 2028 filler_->SetNamedReference(HeapGraphEdge::kWeak, |
| 2032 parent_entry, | 2029 parent_entry, |
| 2033 names_->GetFormatted("%d", index), | 2030 names_->GetFormatted("%d", index), |
| 2034 child_entry); | 2031 child_entry); |
| 2035 } | 2032 } |
| 2036 IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); | 2033 MarkVisitedField(parent_obj, field_offset); |
| 2037 } | 2034 } |
| 2038 | 2035 |
| 2039 | 2036 |
| 2040 void V8HeapExplorer::SetDataOrAccessorPropertyReference( | 2037 void V8HeapExplorer::SetDataOrAccessorPropertyReference( |
| 2041 PropertyKind kind, JSObject* parent_obj, int parent_entry, | 2038 PropertyKind kind, JSObject* parent_obj, int parent_entry, |
| 2042 Name* reference_name, Object* child_obj, const char* name_format_string, | 2039 Name* reference_name, Object* child_obj, const char* name_format_string, |
| 2043 int field_offset) { | 2040 int field_offset) { |
| 2044 if (kind == kAccessor) { | 2041 if (kind == kAccessor) { |
| 2045 ExtractAccessorPairProperty(parent_obj, parent_entry, reference_name, | 2042 ExtractAccessorPairProperty(parent_obj, parent_entry, reference_name, |
| 2046 child_obj, field_offset); | 2043 child_obj, field_offset); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 2067 ? names_->GetFormatted( | 2064 ? names_->GetFormatted( |
| 2068 name_format_string, | 2065 name_format_string, |
| 2069 String::cast(reference_name)->ToCString( | 2066 String::cast(reference_name)->ToCString( |
| 2070 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).get()) : | 2067 DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL).get()) : |
| 2071 names_->GetName(reference_name); | 2068 names_->GetName(reference_name); |
| 2072 | 2069 |
| 2073 filler_->SetNamedReference(type, | 2070 filler_->SetNamedReference(type, |
| 2074 parent_entry, | 2071 parent_entry, |
| 2075 name, | 2072 name, |
| 2076 child_entry); | 2073 child_entry); |
| 2077 IndexedReferencesExtractor::MarkVisitedField(parent_obj, field_offset); | 2074 MarkVisitedField(parent_obj, field_offset); |
| 2078 } | 2075 } |
| 2079 } | 2076 } |
| 2080 | 2077 |
| 2081 | 2078 |
| 2082 void V8HeapExplorer::SetRootGcRootsReference() { | 2079 void V8HeapExplorer::SetRootGcRootsReference() { |
| 2083 filler_->SetIndexedAutoIndexReference( | 2080 filler_->SetIndexedAutoIndexReference( |
| 2084 HeapGraphEdge::kElement, | 2081 HeapGraphEdge::kElement, |
| 2085 snapshot_->root()->index(), | 2082 snapshot_->root()->index(), |
| 2086 snapshot_->gc_roots()); | 2083 snapshot_->gc_roots()); |
| 2087 } | 2084 } |
| (...skipping 1083 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3171 for (int i = 1; i < sorted_strings.length(); ++i) { | 3168 for (int i = 1; i < sorted_strings.length(); ++i) { |
| 3172 writer_->AddCharacter(','); | 3169 writer_->AddCharacter(','); |
| 3173 SerializeString(sorted_strings[i]); | 3170 SerializeString(sorted_strings[i]); |
| 3174 if (writer_->aborted()) return; | 3171 if (writer_->aborted()) return; |
| 3175 } | 3172 } |
| 3176 } | 3173 } |
| 3177 | 3174 |
| 3178 | 3175 |
| 3179 } // namespace internal | 3176 } // namespace internal |
| 3180 } // namespace v8 | 3177 } // namespace v8 |
| OLD | NEW |