blob: 5ec64846015ec7d19d011e3125ada144da27d40a [file] [log] [blame]
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +00001// 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 "heap-snapshot-generator.h"
33#include "frames-inl.h"
34
35namespace v8 {
36namespace internal {
37
38AllocationTraceNode::AllocationTraceNode(
39 AllocationTraceTree* tree, SnapshotObjectId shared_function_info_id)
40 : tree_(tree),
41 function_id_(shared_function_info_id),
42 total_size_(0),
43 allocation_count_(0),
44 id_(tree->next_node_id()) {
45}
46
47
48AllocationTraceNode::~AllocationTraceNode() {
bmeurer@chromium.org25530ce2014-02-07 09:11:16 +000049 for (int i = 0; i < children_.length(); i++) delete children_[i];
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +000050}
51
52
53AllocationTraceNode* AllocationTraceNode::FindChild(SnapshotObjectId id) {
54 for (int i = 0; i < children_.length(); i++) {
55 AllocationTraceNode* node = children_[i];
56 if (node->function_id() == id) return node;
57 }
58 return NULL;
59}
60
61
62AllocationTraceNode* AllocationTraceNode::FindOrAddChild(SnapshotObjectId id) {
63 AllocationTraceNode* child = FindChild(id);
64 if (child == NULL) {
65 child = new AllocationTraceNode(tree_, id);
66 children_.Add(child);
67 }
68 return child;
69}
70
71
72void AllocationTraceNode::AddAllocation(unsigned size) {
73 total_size_ += size;
74 ++allocation_count_;
75}
76
77
78void AllocationTraceNode::Print(int indent, AllocationTracker* tracker) {
79 OS::Print("%10u %10u %*c", total_size_, allocation_count_, indent, ' ');
80 if (tracker != NULL) {
81 const char* name = "<unknown function>";
82 if (function_id_ != 0) {
83 AllocationTracker::FunctionInfo* info =
84 tracker->GetFunctionInfo(function_id_);
85 if (info != NULL) {
86 name = info->name;
87 }
88 }
89 OS::Print("%s #%u", name, id_);
90 } else {
91 OS::Print("%u #%u", function_id_, id_);
92 }
93 OS::Print("\n");
94 indent += 2;
95 for (int i = 0; i < children_.length(); i++) {
96 children_[i]->Print(indent, tracker);
97 }
98}
99
100
101AllocationTraceTree::AllocationTraceTree()
102 : next_node_id_(1),
103 root_(this, 0) {
104}
105
106
107AllocationTraceTree::~AllocationTraceTree() {
108}
109
110
111AllocationTraceNode* AllocationTraceTree::AddPathFromEnd(
112 const Vector<SnapshotObjectId>& path) {
113 AllocationTraceNode* node = root();
114 for (SnapshotObjectId* entry = path.start() + path.length() - 1;
115 entry != path.start() - 1;
116 --entry) {
117 node = node->FindOrAddChild(*entry);
118 }
119 return node;
120}
121
122
123void AllocationTraceTree::Print(AllocationTracker* tracker) {
124 OS::Print("[AllocationTraceTree:]\n");
125 OS::Print("Total size | Allocation count | Function id | id\n");
126 root()->Print(0, tracker);
127}
128
129void AllocationTracker::DeleteUnresolvedLocation(
130 UnresolvedLocation** location) {
131 delete *location;
132}
133
134
135AllocationTracker::FunctionInfo::FunctionInfo()
136 : name(""),
137 script_name(""),
138 script_id(0),
139 line(-1),
140 column(-1) {
141}
142
143
144static bool AddressesMatch(void* key1, void* key2) {
145 return key1 == key2;
146}
147
148
149AllocationTracker::AllocationTracker(
150 HeapObjectsMap* ids, StringsStorage* names)
151 : ids_(ids),
152 names_(names),
153 id_to_function_info_(AddressesMatch) {
154}
155
156
157AllocationTracker::~AllocationTracker() {
158 unresolved_locations_.Iterate(DeleteUnresolvedLocation);
bmeurer@chromium.org25530ce2014-02-07 09:11:16 +0000159 for (HashMap::Entry* p = id_to_function_info_.Start();
160 p != NULL;
161 p = id_to_function_info_.Next(p)) {
162 delete reinterpret_cast<AllocationTracker::FunctionInfo* >(p->value);
163 }
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000164}
165
166
167void AllocationTracker::PrepareForSerialization() {
168 List<UnresolvedLocation*> copy(unresolved_locations_.length());
169 copy.AddAll(unresolved_locations_);
170 unresolved_locations_.Clear();
171 for (int i = 0; i < copy.length(); i++) {
172 copy[i]->Resolve();
173 delete copy[i];
174 }
175}
176
177
yangguo@chromium.orgcc536052013-11-29 11:43:20 +0000178void AllocationTracker::AllocationEvent(Address addr, int size) {
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000179 DisallowHeapAllocation no_allocation;
180 Heap* heap = ids_->heap();
181
182 // Mark the new block as FreeSpace to make sure the heap is iterable
183 // while we are capturing stack trace.
184 FreeListNode::FromAddress(addr)->set_size(heap, size);
185 ASSERT_EQ(HeapObject::FromAddress(addr)->Size(), size);
186 ASSERT(FreeListNode::IsFreeListNode(HeapObject::FromAddress(addr)));
187
188 Isolate* isolate = heap->isolate();
189 int length = 0;
190 StackTraceFrameIterator it(isolate);
191 while (!it.done() && length < kMaxAllocationTraceLength) {
192 JavaScriptFrame* frame = it.frame();
193 SharedFunctionInfo* shared = frame->function()->shared();
yangguo@chromium.orgcc536052013-11-29 11:43:20 +0000194 SnapshotObjectId id = ids_->FindOrAddEntry(
195 shared->address(), shared->Size(), false);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000196 allocation_trace_buffer_[length++] = id;
197 AddFunctionInfo(shared, id);
198 it.Advance();
199 }
200 AllocationTraceNode* top_node = trace_tree_.AddPathFromEnd(
201 Vector<SnapshotObjectId>(allocation_trace_buffer_, length));
202 top_node->AddAllocation(size);
203}
204
205
206static uint32_t SnapshotObjectIdHash(SnapshotObjectId id) {
207 return ComputeIntegerHash(static_cast<uint32_t>(id),
208 v8::internal::kZeroHashSeed);
209}
210
211
212AllocationTracker::FunctionInfo* AllocationTracker::GetFunctionInfo(
213 SnapshotObjectId id) {
214 HashMap::Entry* entry = id_to_function_info_.Lookup(
215 reinterpret_cast<void*>(id), SnapshotObjectIdHash(id), false);
216 if (entry == NULL) {
217 return NULL;
218 }
219 return reinterpret_cast<FunctionInfo*>(entry->value);
220}
221
222
223void AllocationTracker::AddFunctionInfo(SharedFunctionInfo* shared,
224 SnapshotObjectId id) {
225 HashMap::Entry* entry = id_to_function_info_.Lookup(
226 reinterpret_cast<void*>(id), SnapshotObjectIdHash(id), true);
227 if (entry->value == NULL) {
228 FunctionInfo* info = new FunctionInfo();
229 info->name = names_->GetFunctionName(shared->DebugName());
230 if (shared->script()->IsScript()) {
231 Script* script = Script::cast(shared->script());
232 if (script->name()->IsName()) {
233 Name* name = Name::cast(script->name());
234 info->script_name = names_->GetName(name);
235 }
236 info->script_id = script->id()->value();
237 // Converting start offset into line and column may cause heap
238 // allocations so we postpone them until snapshot serialization.
239 unresolved_locations_.Add(new UnresolvedLocation(
240 script,
241 shared->start_position(),
242 info));
243 }
244 entry->value = info;
245 }
246}
247
248
249AllocationTracker::UnresolvedLocation::UnresolvedLocation(
250 Script* script, int start, FunctionInfo* info)
251 : start_position_(start),
252 info_(info) {
253 script_ = Handle<Script>::cast(
254 script->GetIsolate()->global_handles()->Create(script));
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000255 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
256 this,
257 &HandleWeakScript);
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000258}
259
260
261AllocationTracker::UnresolvedLocation::~UnresolvedLocation() {
262 if (!script_.is_null()) {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000263 GlobalHandles::Destroy(reinterpret_cast<Object**>(script_.location()));
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000264 }
265}
266
267
268void AllocationTracker::UnresolvedLocation::Resolve() {
269 if (script_.is_null()) return;
270 info_->line = GetScriptLineNumber(script_, start_position_);
271 info_->column = GetScriptColumnNumber(script_, start_position_);
272}
273
274
275void AllocationTracker::UnresolvedLocation::HandleWeakScript(
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000276 const v8::WeakCallbackData<v8::Value, void>& data) {
277 UnresolvedLocation* loc =
278 reinterpret_cast<UnresolvedLocation*>(data.GetParameter());
279 GlobalHandles::Destroy(reinterpret_cast<Object**>(loc->script_.location()));
280 loc->script_ = Handle<Script>::null();
machenbach@chromium.orgb5be0a92013-11-15 10:32:41 +0000281}
282
283
284} } // namespace v8::internal