v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
allocation-tracker.cc
Go to the documentation of this file.
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
3// found in the LICENSE file.
4
6
7#include "src/api/api-inl.h"
8#include "src/api/api.h"
13#include "src/utils/utils.h"
14
15namespace v8 {
16namespace internal {
17
19 AllocationTraceTree* tree, unsigned function_info_index)
20 : tree_(tree),
21 function_info_index_(function_info_index),
22 total_size_(0),
23 allocation_count_(0),
24 id_(tree->next_node_id()) {
25}
26
27
31
32
34 unsigned function_info_index) {
35 for (AllocationTraceNode* node : children_) {
36 if (node->function_info_index() == function_info_index) return node;
37 }
38 return nullptr;
39}
40
41
43 unsigned function_info_index) {
45 if (child == nullptr) {
47 children_.push_back(child);
48 }
49 return child;
50}
51
52
57
58
60 base::OS::Print("%10u %10u %*c", total_size_, allocation_count_, indent, ' ');
61 if (tracker != nullptr) {
64 base::OS::Print("%s #%u", info->name, id_);
65 } else {
66 base::OS::Print("%u #%u", function_info_index_, id_);
67 }
68 base::OS::Print("\n");
69 indent += 2;
70 for (AllocationTraceNode* node : children_) {
71 node->Print(indent, tracker);
72 }
73}
74
75
77 : next_node_id_(1),
78 root_(this, 0) {
79}
80
83 AllocationTraceNode* node = root();
84 for (const unsigned* entry = path.begin() + path.length() - 1;
85 entry != path.begin() - 1; --entry) {
86 node = node->FindOrAddChild(*entry);
87 }
88 return node;
89}
90
92 base::OS::Print("[AllocationTraceTree:]\n");
93 base::OS::Print("Total size | Allocation count | Function id | id\n");
94 root()->Print(0, tracker);
95}
96
98 : name(""),
99 function_id(0),
100 script_name(""),
101 script_id(0),
102 start_position(-1),
103 line(-1),
104 column(-1) {}
105
107 unsigned trace_node_id) {
108 Address end = start + size;
109 RemoveRange(start, end);
110
111 RangeStack new_range(start, trace_node_id);
112 ranges_.insert(RangeMap::value_type(end, new_range));
113}
114
115
117 RangeMap::const_iterator it = ranges_.upper_bound(addr);
118 if (it == ranges_.end()) return 0;
119 if (it->second.start <= addr) {
120 return it->second.trace_node_id;
121 }
122 return 0;
123}
124
125
127 unsigned trace_node_id = GetTraceNodeId(from);
128 if (trace_node_id == 0) return;
129 RemoveRange(from, from + size);
130 AddRange(to, size, trace_node_id);
131}
132
133
135 ranges_.clear();
136}
137
138
140 PrintF("[AddressToTraceMap (%zu): \n", ranges_.size());
141 for (RangeMap::iterator it = ranges_.begin(); it != ranges_.end(); ++it) {
142 PrintF("[%p - %p] => %u\n", reinterpret_cast<void*>(it->second.start),
143 reinterpret_cast<void*>(it->first), it->second.trace_node_id);
144 }
145 PrintF("]\n");
146}
147
148
150 RangeMap::iterator it = ranges_.upper_bound(start);
151 if (it == ranges_.end()) return;
152
153 RangeStack prev_range(0, 0);
154
155 RangeMap::iterator to_remove_begin = it;
156 if (it->second.start < start) {
157 prev_range = it->second;
158 }
159 do {
160 if (it->first > end) {
161 if (it->second.start < end) {
162 it->second.start = end;
163 }
164 break;
165 }
166 ++it;
167 } while (it != ranges_.end());
168
169 ranges_.erase(to_remove_begin, it);
170
171 if (prev_range.start != 0) {
172 ranges_.insert(RangeMap::value_type(start, prev_range));
173 }
174}
175
177 : ids_(ids),
178 names_(names),
181 FunctionInfo* info = new FunctionInfo();
182 info->name = "(root)";
183 function_info_list_.push_back(info);
184}
185
189
192 Heap* heap = ids_->heap();
193
194 // Mark the new block as FreeSpace to make sure the heap is iterable
195 // while we are capturing stack trace.
196 heap->CreateFillerObjectAt(addr, size);
197
198 Isolate* isolate = Isolate::FromHeap(heap);
199 int length = 0;
201 while (!it.done() && length < kMaxAllocationTraceLength) {
202 JavaScriptFrame* frame = it.frame();
203 Tagged<SharedFunctionInfo> shared = frame->function()->shared();
205 ids_->FindOrAddEntry(shared.address(), shared->Size(),
207 allocation_trace_buffer_[length++] = AddFunctionInfo(shared, id, isolate);
208 it.Advance();
209 }
210 if (length == 0) {
211 unsigned index = functionInfoIndexForVMState(isolate->current_vm_state());
212 if (index != 0) {
214 }
215 }
218 top_node->AddAllocation(size);
219
220 address_to_trace_.AddRange(addr, size, top_node->id());
221}
222
223
225 return ComputeUnseededHash(static_cast<uint32_t>(id));
226}
227
229 Isolate* isolate,
230 AllocationTracker* tracker)
231 : script_id_(script->id()),
232 line_ends_(Script::GetLineEnds(isolate, direct_handle(script, isolate))),
233 tracker_(tracker) {
234 DirectHandle<Script> script_direct_handle(script, isolate);
235 auto local_script = ToApiHandle<debug::Script>(script_direct_handle);
236 script_.Reset(local_script->GetIsolate(), local_script);
238}
239
241 if (!script_.IsEmpty()) {
242 script_.ClearWeak();
243 }
244}
245
248 ScriptData* script_data = reinterpret_cast<ScriptData*>(data.GetParameter());
249 script_data->script_.ClearWeak();
250 script_data->script_.Reset();
251 script_data->tracker_->scripts_data_map_.erase(script_data->script_id_);
252}
253
255 Tagged<Script> script, Isolate* isolate) {
256 auto it = scripts_data_map_.find(script->id());
257 if (it == scripts_data_map_.end()) {
258 auto inserted =
259 scripts_data_map_.try_emplace(script->id(), script, isolate, this);
260 CHECK(inserted.second);
261 return inserted.first->second.line_ends();
262 } else {
263 return it->second.line_ends();
264 }
265}
266
268 Tagged<Script> script, Isolate* isolate, int start) {
269 Script::PositionInfo position_info;
270 if (script->has_line_ends()) {
271 script->GetPositionInfo(start, &position_info);
272 } else {
273 script->GetPositionInfoWithLineEnds(start, &position_info,
274 GetOrCreateLineEnds(script, isolate));
275 }
276 return position_info;
277}
278
281 Isolate* isolate) {
283 reinterpret_cast<void*>(id), SnapshotObjectIdHash(id));
284 if (entry->value == nullptr) {
285 FunctionInfo* info = new FunctionInfo();
286 info->name = names_->GetCopy(shared->DebugNameCStr().get());
287 info->function_id = id;
288 if (IsScript(shared->script())) {
289 Tagged<Script> script = Cast<Script>(shared->script());
290 if (IsName(script->name())) {
291 Tagged<Name> name = Cast<Name>(script->name());
292 info->script_name = names_->GetName(name);
293 }
294 info->script_id = script->id();
295 info->start_position = shared->StartPosition();
296 Script::PositionInfo position_info =
297 GetScriptPositionInfo(script, isolate, info->start_position);
298 info->line = position_info.line;
299 info->column = position_info.column;
300 }
301 entry->value = reinterpret_cast<void*>(function_info_list_.size());
302 function_info_list_.push_back(info);
303 }
304 return static_cast<unsigned>(reinterpret_cast<intptr_t>((entry->value)));
305}
306
308 if (state != OTHER) return 0;
310 FunctionInfo* info = new FunctionInfo();
311 info->name = "(V8 API)";
313 static_cast<unsigned>(function_info_list_.size());
314 function_info_list_.push_back(info);
315 }
317}
318
319} // namespace internal
320} // namespace v8
Entry * LookupOrInsert(const Key &key, uint32_t hash)
Definition hashmap.h:223
int length() const
Definition vector.h:64
constexpr T * begin() const
Definition vector.h:96
void MoveObject(Address from, Address to, int size)
void AddRange(Address addr, int size, unsigned node_id)
void RemoveRange(Address start, Address end)
unsigned GetTraceNodeId(Address addr)
std::vector< AllocationTraceNode * > children_
AllocationTraceNode * FindOrAddChild(unsigned function_info_index)
AllocationTraceNode(AllocationTraceTree *tree, unsigned function_info_index)
void Print(int indent, AllocationTracker *tracker)
AllocationTraceNode * FindChild(unsigned function_info_index)
AllocationTraceNode * AddPathFromEnd(base::Vector< const unsigned > path)
V8_EXPORT_PRIVATE void Print(AllocationTracker *tracker)
static void HandleWeakScript(const v8::WeakCallbackInfo< ScriptData > &)
ScriptData(Tagged< Script >, Isolate *, AllocationTracker *)
unsigned functionInfoIndexForVMState(StateTag state)
unsigned allocation_trace_buffer_[kMaxAllocationTraceLength]
unsigned AddFunctionInfo(Tagged< SharedFunctionInfo > info, SnapshotObjectId id, Isolate *isolate)
std::vector< FunctionInfo * > function_info_list_
Script::PositionInfo GetScriptPositionInfo(Tagged< Script > script, Isolate *isolate, int start)
String::LineEndsVector & GetOrCreateLineEnds(Tagged< Script > script, Isolate *isolate)
AllocationTracker(HeapObjectsMap *ids, StringsStorage *names)
void AllocationEvent(Address addr, int size)
const std::vector< FunctionInfo * > & function_info_list() const
SnapshotObjectId FindOrAddEntry(Address addr, unsigned int size, MarkEntryAccessed accessed=MarkEntryAccessed::kYes, IsNativeObject is_native_object=IsNativeObject::kNo)
static Isolate * FromHeap(const Heap *heap)
Definition isolate.h:1202
Tagged< JSFunction > function() const override
Definition frames.cc:2492
const char * GetCopy(const char *src)
const char * GetName(Tagged< Name > name)
int start
Handle< SharedFunctionInfo > info
int end
Handle< Script > script_
Node * node
void PrintF(const char *format,...)
Definition utils.cc:39
uint32_t ComputeUnseededHash(uint32_t key)
Definition utils.h:271
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
static uint32_t SnapshotObjectIdHash(SnapshotObjectId id)
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
v8::Local< T > ToApiHandle(v8::internal::DirectHandle< v8::internal::Object > obj)
Definition api.h:297
uint32_t SnapshotObjectId
Definition v8-profiler.h:31
StateTag
Definition v8-unwinder.h:36
@ OTHER
Definition v8-unwinder.h:42
#define CHECK(condition)
Definition logging.h:124
int script_id_