Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
object_graph.h
Go to the documentation of this file.
1// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_OBJECT_GRAPH_H_
6#define RUNTIME_VM_OBJECT_GRAPH_H_
7
8#include <memory>
9
10#include "vm/allocation.h"
11#include "vm/dart_api_state.h"
13
14namespace dart {
15
16class Array;
17class Object;
18class CountingPage;
19
20#if defined(DART_ENABLE_HEAP_SNAPSHOT_WRITER)
21
22// Utility to traverse the object graph in an ordered fashion.
23// Example uses:
24// - find a retaining path from the isolate roots to a particular object, or
25// - determine how much memory is retained by some particular object(s).
26class ObjectGraph : public ThreadStackResource {
27 public:
28 class Stack;
29
30 // Allows climbing the search tree all the way to the root.
31 class StackIterator {
32 public:
33 // The object this iterator currently points to.
34 ObjectPtr Get() const;
35 // Returns false if there is no parent.
36 bool MoveToParent();
37 // Offset into parent for the pointer to current object. -1 if no parent.
38 intptr_t OffsetFromParent() const;
39
40 private:
41 StackIterator(const Stack* stack, intptr_t index)
42 : stack_(stack), index_(index) {}
43 const Stack* stack_;
44 intptr_t index_;
45 friend class ObjectGraph::Stack;
46 DISALLOW_IMPLICIT_CONSTRUCTORS(StackIterator);
47 };
48
49 class Visitor {
50 public:
51 // Directs how the search should continue after visiting an object.
52 enum Direction {
53 kProceed, // Recurse on this object's pointers.
54 kBacktrack, // Ignore this object's pointers.
55 kAbort, // Terminate the entire search immediately.
56 };
57 virtual ~Visitor() {}
58 // Visits the object pointed to by *it. The iterator is only valid
59 // during this call. This method must not allocate from the heap or
60 // trigger GC in any way.
61 virtual Direction VisitObject(StackIterator* it) = 0;
62
63 virtual bool visit_weak_persistent_handles() const { return false; }
64
65 const char* gc_root_type = nullptr;
66 bool is_traversing = false;
67 };
68
69 typedef struct {
70 intptr_t length;
71 const char* gc_root_type;
72 } RetainingPathResult;
73
74 explicit ObjectGraph(Thread* thread);
75 ~ObjectGraph();
76
77 // Visits all strongly reachable objects in the isolate's heap, in a
78 // pre-order, depth first traversal.
79 void IterateObjects(Visitor* visitor);
80 void IterateUserObjects(Visitor* visitor);
81
82 // Like 'IterateObjects', but restricted to objects reachable from 'root'
83 // (including 'root' itself).
84 void IterateObjectsFrom(const Object& root, Visitor* visitor);
85 void IterateObjectsFrom(intptr_t class_id,
86 HeapIterationScope* iteration,
87 Visitor* visitor);
88
89 // The number of bytes retained by 'obj'.
90 intptr_t SizeRetainedByInstance(const Object& obj);
91 intptr_t SizeReachableByInstance(const Object& obj);
92
93 // The number of bytes retained by the set of all objects of the given class.
94 intptr_t SizeRetainedByClass(intptr_t class_id);
95 intptr_t SizeReachableByClass(intptr_t class_id);
96
97 // Finds some retaining path from the isolate roots to 'obj'. Populates the
98 // provided array with pairs of (object, offset from parent in words),
99 // starting with 'obj' itself, as far as there is room. Returns the number
100 // of objects on the full path. A null input array behaves like a zero-length
101 // input array. The 'offset' of a root is -1.
102 //
103 // To break the trivial path, the handle 'obj' is temporarily cleared during
104 // the search, but restored before returning. If no path is found (i.e., the
105 // provided handle was the only way to reach the object), zero is returned.
106 RetainingPathResult RetainingPath(Object* obj, const Array& path);
107
108 // Find the objects that reference 'obj'. Populates the provided array with
109 // pairs of (object pointing to 'obj', offset of pointer in words), as far as
110 // there is room. Returns the number of objects found.
111 //
112 // An object for which this function answers no inbound references might still
113 // be live due to references from the stack or embedder handles.
114 intptr_t InboundReferences(Object* obj, const Array& references);
115
116 private:
118};
119
120class ChunkedWriter : public ThreadStackResource {
121 public:
122 explicit ChunkedWriter(Thread* thread) : ThreadStackResource(thread) {}
123
124 virtual intptr_t ReserveChunkPrefixSize() { return 0; }
125
126 // Takes ownership of [buffer], must be freed with [malloc].
127 virtual void WriteChunk(uint8_t* buffer, intptr_t size, bool last) = 0;
128};
129
130class FileHeapSnapshotWriter : public ChunkedWriter {
131 public:
132 FileHeapSnapshotWriter(Thread* thread,
133 const char* filename,
134 bool* success = nullptr);
135 ~FileHeapSnapshotWriter();
136
137 virtual void WriteChunk(uint8_t* buffer, intptr_t size, bool last);
138
139 private:
140 void* file_ = nullptr;
141 bool* success_;
142};
143
144class CallbackHeapSnapshotWriter : public ChunkedWriter {
145 public:
146 CallbackHeapSnapshotWriter(Thread* thread,
148 void* context);
149 ~CallbackHeapSnapshotWriter();
150
151 virtual void WriteChunk(uint8_t* buffer, intptr_t size, bool last);
152
153 private:
155 void* context_;
156};
157
158class VmServiceHeapSnapshotChunkedWriter : public ChunkedWriter {
159 public:
160 explicit VmServiceHeapSnapshotChunkedWriter(Thread* thread)
161 : ChunkedWriter(thread) {}
162
163 virtual intptr_t ReserveChunkPrefixSize() { return kMetadataReservation; }
164 virtual void WriteChunk(uint8_t* buffer, intptr_t size, bool last);
165
166 private:
167 static constexpr intptr_t kMetadataReservation = 512;
168};
169
170// Generates a dump of the heap, whose format is described in
171// runtime/vm/service/heap_snapshot.md.
172class HeapSnapshotWriter : public ThreadStackResource {
173 public:
174 HeapSnapshotWriter(Thread* thread, ChunkedWriter* writer)
175 : ThreadStackResource(thread), writer_(writer) {}
176 ~HeapSnapshotWriter() { free(image_page_ranges_); }
177
178 void WriteSigned(int64_t value) {
179 EnsureAvailable((sizeof(value) * kBitsPerByte) / 7 + 1);
180
181 bool is_last_part = false;
182 while (!is_last_part) {
183 uint8_t part = value & 0x7F;
184 value >>= 7;
185 if ((value == 0 && (part & 0x40) == 0) ||
186 (value == static_cast<intptr_t>(-1) && (part & 0x40) != 0)) {
187 is_last_part = true;
188 } else {
189 part |= 0x80;
190 }
191 buffer_[size_++] = part;
192 }
193 }
194
195 void WriteUnsigned(uintptr_t value) {
196 EnsureAvailable((sizeof(value) * kBitsPerByte) / 7 + 1);
197
198 bool is_last_part = false;
199 while (!is_last_part) {
200 uint8_t part = value & 0x7F;
201 value >>= 7;
202 if (value == 0) {
203 is_last_part = true;
204 } else {
205 part |= 0x80;
206 }
207 buffer_[size_++] = part;
208 }
209 }
210
211 void WriteBytes(const void* bytes, intptr_t len) {
212 EnsureAvailable(len);
213 memmove(&buffer_[size_], bytes, len);
214 size_ += len;
215 }
216
217 void ScrubAndWriteUtf8(char* value) {
218 intptr_t len = strlen(value);
219 for (intptr_t i = len - 1; i >= 0; i--) {
220 if (value[i] == '@') {
221 value[i] = '\0';
222 }
223 }
224 WriteUtf8(value);
225 }
226
227 void WriteUtf8(const char* value) {
228 intptr_t len = strlen(value);
229 WriteUnsigned(len);
230 WriteBytes(value, len);
231 }
232
233 void AssignObjectId(ObjectPtr obj);
234 intptr_t GetObjectId(ObjectPtr obj) const;
235 void ClearObjectIds();
236 void CountReferences(intptr_t count);
237 void CountExternalProperty();
238 void AddSmi(SmiPtr smi);
239
240 void Write();
241
242 static uint32_t GetHeapSnapshotIdentityHash(Thread* thread, ObjectPtr obj);
243
244 private:
245 static uint32_t GetHashHelper(Thread* thread, ObjectPtr obj);
246
247 static constexpr intptr_t kPreferredChunkSize = MB;
248
249 void SetupImagePageBoundaries();
250 void SetupCountingPages();
251 bool OnImagePage(ObjectPtr obj) const;
252 CountingPage* FindCountingPage(ObjectPtr obj) const;
253
254 void EnsureAvailable(intptr_t needed);
255 void Flush(bool last = false);
256
257 ChunkedWriter* writer_ = nullptr;
258
259 uint8_t* buffer_ = nullptr;
260 intptr_t size_ = 0;
261 intptr_t capacity_ = 0;
262
263 intptr_t class_count_ = 0;
264 intptr_t object_count_ = 0;
265 intptr_t reference_count_ = 0;
266 intptr_t external_property_count_ = 0;
267
268 struct ImagePageRange {
269 uword start;
270 uword end;
271 };
272 static int CompareImagePageRanges(const ImagePageRange* a,
273 const ImagePageRange* b) {
274 if (a->start < b->start) {
275 return -1;
276 } else if (a->start == b->start) {
277 return 0;
278 } else {
279 return 1;
280 }
281 }
282 intptr_t image_page_hi_ = 0;
283 ImagePageRange* image_page_ranges_ = nullptr;
284
285 MallocGrowableArray<SmiPtr> smis_;
286
287 DISALLOW_COPY_AND_ASSIGN(HeapSnapshotWriter);
288};
289
290class CountObjectsVisitor : public ObjectVisitor, public HandleVisitor {
291 public:
292 CountObjectsVisitor(Thread* thread, intptr_t class_count);
293 ~CountObjectsVisitor() {}
294
295 void VisitObject(ObjectPtr obj) override;
296 void VisitHandle(uword addr) override;
297
298 std::unique_ptr<intptr_t[]> new_count_;
299 std::unique_ptr<intptr_t[]> new_size_;
300 std::unique_ptr<intptr_t[]> new_external_size_;
301 std::unique_ptr<intptr_t[]> old_count_;
302 std::unique_ptr<intptr_t[]> old_size_;
303 std::unique_ptr<intptr_t[]> old_external_size_;
304
305 DISALLOW_COPY_AND_ASSIGN(CountObjectsVisitor);
306};
307
308#endif // !defined(DART_ENABLE_HEAP_SNAPSHOT_WRITER)
309
310} // namespace dart
311
312#endif // RUNTIME_VM_OBJECT_GRAPH_H_
int count
void(* Dart_HeapSnapshotWriteChunkCallback)(void *context, uint8_t *buffer, intptr_t size, bool is_last)
static bool b
struct MyStruct a[10]
glong glong end
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static const uint8_t buffer[]
uint8_t value
size_t length
const GrXPFactory * Get(SkBlendMode mode)
Visitor(Ts...) -> Visitor< Ts... >
constexpr intptr_t MB
Definition globals.h:530
uintptr_t uword
Definition globals.h:501
void Flush(SkSurface *surface)
Definition GpuTools.h:25
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName)
Definition globals.h:593
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581