Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | |
| 2 // Redistribution and use in source and binary forms, with or without | |
| 3 // modification, are permitted provided that the following conditions are | |
| 4 // met: | |
| 5 // | |
| 6 // * Redistributions of source code must retain the above copyright | |
| 7 // notice, this list of conditions and the following disclaimer. | |
| 8 // * Redistributions in binary form must reproduce the above | |
| 9 // copyright notice, this list of conditions and the following | |
| 10 // disclaimer in the documentation and/or other materials provided | |
| 11 // with the distribution. | |
| 12 // * Neither the name of Google Inc. nor the names of its | |
| 13 // contributors may be used to endorse or promote products derived | |
| 14 // from this software without specific prior written permission. | |
| 15 // | |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 27 | |
| 28 #include "v8.h" | |
| 29 | |
| 30 #include "allocation-tracker.h" | |
| 31 | |
| 32 #include "frames-inl.h" | |
| 33 | |
| 34 namespace v8 { | |
| 35 namespace internal { | |
| 36 | |
| 37 AllocationTraceNode::AllocationTraceNode( | |
| 38 AllocationTraceTree* tree, SnapshotObjectId shared_function_info_id) | |
| 39 : tree_(tree), | |
| 40 function_id_(shared_function_info_id), | |
| 41 total_size_(0), | |
| 42 allocation_count_(0), | |
| 43 id_(tree->next_node_id()) { | |
| 44 } | |
| 45 | |
| 46 | |
| 47 AllocationTraceNode::~AllocationTraceNode() { | |
| 48 } | |
| 49 | |
| 50 | |
| 51 AllocationTraceNode* AllocationTraceNode::FindChild(SnapshotObjectId id) { | |
| 52 for (int i = 0; i < children_.length(); i++) { | |
| 53 AllocationTraceNode* node = children_[i]; | |
| 54 if (node->function_id() == id) return node; | |
| 55 } | |
| 56 return NULL; | |
| 57 } | |
| 58 | |
| 59 | |
| 60 AllocationTraceNode* AllocationTraceNode::FindOrAddChild(SnapshotObjectId id) { | |
| 61 AllocationTraceNode* child = FindChild(id); | |
| 62 if (child == NULL) { | |
| 63 child = new AllocationTraceNode(tree_, id); | |
| 64 children_.Add(child); | |
| 65 } | |
| 66 return child; | |
| 67 } | |
| 68 | |
| 69 | |
| 70 void AllocationTraceNode::AddAllocation(unsigned size) { | |
| 71 total_size_ += size; | |
| 72 ++allocation_count_; | |
| 73 } | |
| 74 | |
| 75 | |
| 76 void AllocationTraceNode::Print(int indent) { | |
| 77 OS::Print("%10u %10u %*c %u #%u", | |
| 78 total_size_, allocation_count_, | |
| 79 indent, ' ', | |
| 80 function_id_, | |
| 81 id_); | |
| 82 OS::Print("\n"); | |
| 83 indent += 2; | |
| 84 for (int i = 0; i < children_.length(); i++) { | |
| 85 children_[i]->Print(indent); | |
| 86 } | |
| 87 } | |
| 88 | |
| 89 | |
| 90 AllocationTraceTree::AllocationTraceTree() | |
| 91 : next_node_id_(1), | |
| 92 root_(this, 0) { | |
| 93 } | |
| 94 | |
| 95 | |
| 96 AllocationTraceTree::~AllocationTraceTree() { | |
| 97 } | |
| 98 | |
| 99 | |
| 100 AllocationTraceNode* AllocationTraceTree::AddPathFromEnd( | |
| 101 const Vector<SnapshotObjectId>& path) { | |
| 102 AllocationTraceNode* node = root(); | |
| 103 for (SnapshotObjectId* entry = path.start() + path.length() - 1; | |
| 104 entry != path.start() - 1; | |
| 105 --entry) { | |
| 106 node = node->FindOrAddChild(*entry); | |
| 107 } | |
| 108 return node; | |
| 109 } | |
| 110 | |
| 111 | |
| 112 void AllocationTraceTree::Print() { | |
| 113 OS::Print("[AllocationTraceTree:]\n"); | |
| 114 OS::Print("Total size | Allocation count | Function id | id\n"); | |
| 115 root()->Print(0); | |
| 116 } | |
| 117 | |
| 118 void AllocationTracker::DeleteUnresolvedLocation( | |
| 119 UnresolvedLocation** location) { | |
| 120 delete *location; | |
| 121 } | |
| 122 | |
| 123 | |
| 124 static bool AddressesMatch(void* key1, void* key2) { | |
| 125 return key1 == key2; | |
| 126 } | |
| 127 | |
| 128 | |
| 129 AllocationTracker::AllocationTracker( | |
| 130 HeapObjectsMap* ids, StringsStorage* names) | |
| 131 : ids_(ids), | |
| 132 names_(names), | |
| 133 id_to_function_info_(AddressesMatch) { | |
| 134 } | |
| 135 | |
| 136 | |
| 137 AllocationTracker::~AllocationTracker() { | |
| 138 unresolved_locations_.Iterate(DeleteUnresolvedLocation); | |
| 139 } | |
| 140 | |
| 141 | |
| 142 void AllocationTracker::PrepareForSerialization() { | |
| 143 List<UnresolvedLocation*> copy(unresolved_locations_.length()); | |
| 144 copy.AddAll(unresolved_locations_); | |
| 145 unresolved_locations_.Clear(); | |
| 146 for (int i = 0; i < copy.length(); i++) { | |
| 147 copy[i]->Resolve(); | |
| 148 delete copy[i]; | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 | |
| 153 void AllocationTracker::NewObjectEvent(Address addr, int size) { | |
| 154 DisallowHeapAllocation no_allocation; | |
| 155 Isolate* isolate = ids_->heap()->isolate(); | |
| 156 int length = 0; | |
| 157 StackTraceFrameIterator it(isolate); | |
| 158 while (!it.done() && length < kMaxAllocationTraceLength) { | |
| 159 JavaScriptFrame* frame = it.frame(); | |
| 160 SharedFunctionInfo* shared = frame->function()->shared(); | |
| 161 SnapshotObjectId id = ids_->FindEntry(shared->address()); | |
| 162 allocation_trace_buffer_[length++] = id; | |
| 163 AddFunctionInfo(shared, id); | |
| 164 it.Advance(); | |
| 165 } | |
| 166 AllocationTraceNode* top_node = allocation_traces_.AddPathFromEnd( | |
| 167 Vector<SnapshotObjectId>(allocation_trace_buffer_, length)); | |
| 168 top_node->AddAllocation(size); | |
| 169 } | |
| 170 | |
| 171 | |
| 172 static uint32_t SnapshotObjectIdHash(SnapshotObjectId id) { | |
| 173 return ComputeIntegerHash(static_cast<uint32_t>(id), | |
| 174 v8::internal::kZeroHashSeed); | |
| 175 } | |
| 176 | |
| 177 | |
| 178 void AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared, | |
| 179 SnapshotObjectId id) { | |
| 180 HashMap::Entry* entry = id_to_function_info_.Lookup( | |
| 181 reinterpret_cast<void*>(id), SnapshotObjectIdHash(id), true); | |
| 182 if (entry->value == NULL) { | |
| 183 FunctionInfo* info = new FunctionInfo(); | |
| 184 info->name = names_->GetFunctionName(shared->DebugName()); | |
| 185 if (shared->script()->IsScript()) { | |
| 186 Script* script = Script::cast(shared->script()); | |
| 187 if (script->name()->IsName()) { | |
| 188 Name* name = Name::cast(script->name()); | |
| 189 info->script_name = names_->GetFunctionName(name); | |
| 190 } else { | |
| 191 script->name()->PrintLn(); | |
| 192 printf("script->name is not a name\n"); | |
|
loislo
2013/10/16 15:14:08
please remove this
yurys
2013/10/17 15:27:35
Done.
| |
| 193 } | |
| 194 info->script_id = script->id()->value(); | |
| 195 // Converting start offset into line and column may cause heap allocations . | |
|
loislo
2013/10/16 15:14:08
80 symbols
yurys
2013/10/17 15:27:35
Done.
| |
| 196 unresolved_locations_.Add(new UnresolvedLocation( | |
| 197 script, | |
| 198 shared->start_position(), | |
| 199 info)); | |
| 200 } | |
| 201 entry->value = info; | |
| 202 } | |
| 203 } | |
| 204 | |
| 205 | |
| 206 AllocationTracker::UnresolvedLocation::UnresolvedLocation( | |
| 207 Script* script, int start, FunctionInfo* info) | |
| 208 : start_position_(start), | |
| 209 info_(info) { | |
| 210 script_ = script->GetIsolate()->global_handles()->Create(script); | |
| 211 GlobalHandles::MakeWeak( | |
| 212 reinterpret_cast<Object**>(script_.location()), | |
| 213 this, &HandleWeakScript); | |
| 214 } | |
| 215 | |
| 216 | |
| 217 AllocationTracker::UnresolvedLocation::~UnresolvedLocation() { | |
| 218 if (!script_.is_null()) { | |
| 219 script_->GetIsolate()->global_handles()->Destroy( | |
| 220 reinterpret_cast<Object**>(script_.location())); | |
| 221 } | |
| 222 } | |
| 223 | |
| 224 | |
| 225 void AllocationTracker::UnresolvedLocation::Resolve() { | |
| 226 if (script_.is_null()) return; | |
| 227 info_->line = GetScriptLineNumber(script_, start_position_); | |
| 228 info_->column = GetScriptColumnNumber(script_, start_position_); | |
| 229 } | |
| 230 | |
| 231 | |
| 232 void AllocationTracker::UnresolvedLocation::HandleWeakScript( | |
| 233 v8::Isolate* isolate, | |
| 234 v8::Persistent<v8::Value>* obj, | |
| 235 void* data) { | |
| 236 UnresolvedLocation* location = reinterpret_cast<UnresolvedLocation*>(data); | |
| 237 location->script_ = Handle<Script>::null(); | |
| 238 obj->Dispose(); | |
| 239 } | |
| 240 | |
| 241 | |
| 242 } } // namespace v8::internal | |
| OLD | NEW |