Flutter Engine
The Flutter Engine
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
Definition: FontMgrTest.cpp:50
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
uint8_t value
size_t length
const GrXPFactory * Get(SkBlendMode mode)
Visitor(Ts...) -> Visitor< Ts... >
Definition: dart_vm.cc:33
constexpr intptr_t MB
Definition: globals.h:530
void(* callback_)(Dart_Handle)
constexpr intptr_t kBitsPerByte
Definition: globals.h:463
uintptr_t uword
Definition: globals.h:501
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
Definition: switches.h:57
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
string root
Definition: scale_cpu.py:20
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