Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
v8_snapshot_writer.h
Go to the documentation of this file.
1// Copyright (c) 2018, 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_V8_SNAPSHOT_WRITER_H_
6#define RUNTIME_VM_V8_SNAPSHOT_WRITER_H_
7
8#include <utility>
9
10#include "platform/assert.h"
11#include "vm/allocation.h"
12#include "vm/hash_map.h"
13#include "vm/hash_table.h"
14#include "vm/json_writer.h"
15#include "vm/object.h"
16
17namespace dart {
18
19enum class IdSpace : uint8_t {
20 kInvalid = 0, // So default-constructed ObjectIds are invalid.
21 kSnapshot = 1, // Can be VM or Isolate heap, they share ids.
22 kVmText = 2,
23 kIsolateText = 3,
24 kVmData = 4,
25 kIsolateData = 5,
26 kArtificial = 6, // Artificial objects (e.g. the global root).
27 // Change ObjectId::kIdSpaceBits to use last entry if more are added.
28};
29
31 public:
32 struct ObjectId {
35 : encoded_((static_cast<uint64_t>(nonce) << kIdSpaceBits) |
36 static_cast<intptr_t>(space)) {
37 ASSERT(Utils::IsInt(kBitsPerInt64 - kIdSpaceBits, nonce));
38 }
39
40 inline bool operator!=(const ObjectId& other) const {
41 return encoded_ != other.encoded_;
42 }
43 inline bool operator==(const ObjectId& other) const {
44 return !(*this != other);
45 }
46
47 inline uword Hash() const { return Utils::WordHash(encoded_); }
48 inline int64_t nonce() const { return encoded_ >> kIdSpaceBits; }
49 inline IdSpace space() const {
50 return static_cast<IdSpace>(encoded_ & kIdSpaceMask);
51 }
52 inline bool IsArtificial() const { return space() == IdSpace::kArtificial; }
53
54 const char* ToCString(Zone* zone) const;
55 void Write(JSONWriter* writer, const char* property = nullptr) const;
56 void WriteDebug(JSONWriter* writer, const char* property = nullptr) const;
57
58 private:
59 static constexpr size_t kIdSpaceBits =
60 Utils::BitLength(static_cast<int64_t>(IdSpace::kArtificial));
61 static constexpr int64_t kIdSpaceMask =
62 Utils::NBitMask<int64_t>(kIdSpaceBits);
63 static const char* IdSpaceToCString(IdSpace space);
64
65 int64_t encoded_;
66 };
67
68 struct Reference {
69 enum class Type {
73 intptr_t offset; // kElement
74 const char* name; // kProperty
75
76 static Reference Element(intptr_t offset) {
77 return {Type::kElement, offset, nullptr};
78 }
79 static Reference Property(const char* name) {
80 return {Type::kProperty, 0, name};
81 }
82
83 bool IsElement() const { return type == Type::kElement; }
84 };
85
87
88#if !defined(DART_PRECOMPILER)
89 explicit V8SnapshotProfileWriter(Zone* zone) {}
91
92 void SetObjectTypeAndName(const ObjectId& object_id,
93 const char* type,
94 const char* name) {}
95 void AttributeBytesTo(const ObjectId& object_id, size_t num_bytes) {}
96 void AttributeReferenceTo(const ObjectId& from_object_id,
97 const Reference& reference,
98 const ObjectId& to_object_id) {}
99 void AttributeWeakReferenceTo(const ObjectId& from_object_id,
100 const Reference& reference,
101 const ObjectId& to_object_id,
102 const ObjectId& replacement_object_id) {}
103 void AddRoot(const ObjectId& object_id, const char* name = nullptr) {}
104 bool HasId(const ObjectId& object_id) { return false; }
105#else
106 explicit V8SnapshotProfileWriter(Zone* zone);
107 virtual ~V8SnapshotProfileWriter() {}
108
109 // Records that the object referenced by 'object_id' has type 'type'. The
110 // 'type' for all 'Instance's should be 'Instance', not the user-visible type
111 // and use 'name' for the real type instead.
112 void SetObjectTypeAndName(const ObjectId& object_id,
113 const char* type,
114 const char* name);
115
116 // Charges 'num_bytes'-many bytes to 'object_id'. In a clustered snapshot,
117 // objects can have their data spread across multiple sections, so this can be
118 // called multiple times for the same object.
119 void AttributeBytesTo(const ObjectId& object_id, size_t num_bytes);
120
121 // Records that a reference to the object with id 'to_object_id' was written
122 // in order to serialize the object with id 'from_object_id'. This does not
123 // affect the number of bytes charged to 'from_object_id'.
124 void AttributeReferenceTo(const ObjectId& from_object_id,
125 const Reference& reference,
126 const ObjectId& to_object_id);
127
128 // Records that a weak serialization reference to a dropped object
129 // with id 'to_object_id' was written in order to serialize the object with id
130 // 'from_object_id'. 'to_object_id' must be an artificial node and
131 // 'replacement_object_id' is recorded as the replacement for the
132 // dropped object in the snapshot. This does not affect the number of
133 // bytes charged to 'from_object_id'.
134 void AttributeDroppedReferenceTo(const ObjectId& from_object_id,
135 const Reference& reference,
136 const ObjectId& to_object_id,
137 const ObjectId& replacement_object_id);
138
139 // Marks an object as being a root in the graph. Used for analysis of
140 // the graph.
141 void AddRoot(const ObjectId& object_id, const char* name = nullptr);
142
143 // Write to a file in the V8 Snapshot Profile (JSON/.heapsnapshot) format.
144 void Write(const char* file);
145
146 // Whether the given object ID has been added to the profile (via AddRoot,
147 // SetObjectTypeAndName, etc.).
148 bool HasId(const ObjectId& object_id);
149
150 private:
151 static constexpr intptr_t kInvalidString =
153 static constexpr intptr_t kNumNodeFields = 5;
154 static constexpr intptr_t kNumEdgeFields = 3;
155
156 struct Edge {
157 enum class Type : int32_t {
158 kInvalid = -1,
159 kContext = 0,
160 kElement = 1,
161 kProperty = 2,
162 kInternal = 3,
163 kHidden = 4,
164 kShortcut = 5,
165 kWeak = 6,
166 kExtra = 7,
167 };
168
169 Edge() : Edge(nullptr, Type::kInvalid, -1) {}
170 Edge(V8SnapshotProfileWriter* profile_writer, const Reference& reference)
171 : Edge(profile_writer,
172 reference.type == Reference::Type::kElement ? Type::kElement
173 : Type::kProperty,
174 reference.type == Reference::Type::kElement
175 ? reference.offset
176 : profile_writer->strings_.Add(reference.name)) {}
177 Edge(V8SnapshotProfileWriter* profile_writer,
178 Type type,
179 intptr_t name_or_offset)
180 : type(type), name_or_offset(name_or_offset) {}
181
182 inline bool operator!=(const Edge& other) {
183 return type != other.type || name_or_offset != other.name_or_offset;
184 }
185 inline bool operator==(const Edge& other) { return !(*this != other); }
186
187 void Write(V8SnapshotProfileWriter* profile_writer,
188 JSONWriter* writer,
189 const ObjectId& target_id) const;
190 void WriteDebug(V8SnapshotProfileWriter* profile_writer,
191 JSONWriter* writer,
192 const ObjectId& target_id) const;
193
194 Type type;
195 int32_t name_or_offset;
196 };
197
198 struct EdgeToObjectIdMapTrait {
199 using Key = Edge;
200 using Value = ObjectId;
201
202 struct Pair {
203 Pair() : edge{}, target(kArtificialRootId) {}
204 Pair(Key key, Value value) : edge(key), target(value) {}
205 Edge edge;
206 ObjectId target;
207 };
208
209 static Key KeyOf(Pair kv) { return kv.edge; }
210 static Value ValueOf(Pair kv) { return kv.target; }
211 static uword Hash(Key key) {
212 return FinalizeHash(
213 CombineHashes(static_cast<intptr_t>(key.type), key.name_or_offset));
214 }
215 static bool IsKeyEqual(Pair kv, Key key) { return kv.edge == key; }
216 };
217
218 struct EdgeMap : public ZoneDirectChainedHashMap<EdgeToObjectIdMapTrait> {
219 explicit EdgeMap(Zone* zone)
220 : ZoneDirectChainedHashMap<EdgeToObjectIdMapTrait>(zone, 1) {}
221
222 const char* ToCString(V8SnapshotProfileWriter* profile_writer,
223 Zone* zone) const;
224 void WriteDebug(V8SnapshotProfileWriter* profile_writer,
225 JSONWriter* writer,
226 const char* property = nullptr) const;
227 };
228
229 struct NodeInfo {
230 NodeInfo() {}
231 NodeInfo(V8SnapshotProfileWriter* profile_writer,
232 const ObjectId& id,
233 intptr_t type = kInvalidString,
234 intptr_t name = kInvalidString)
235 : id(id),
236 edges(new(profile_writer->zone_) EdgeMap(profile_writer->zone_)),
237 type(type),
238 name(name) {}
239
240 inline bool operator!=(const NodeInfo& other) {
241 return id != other.id || type != other.type || name != other.name ||
242 self_size != other.self_size || edges != other.edges ||
243 offset_ != other.offset_;
244 }
245 inline bool operator==(const NodeInfo& other) { return !(*this != other); }
246
247 void AddEdge(const Edge& edge, const ObjectId& target) {
248 edges->Insert({edge, target});
249 }
250 bool HasEdge(const Edge& edge) { return edges->HasKey(edge); }
251
252 const char* ToCString(V8SnapshotProfileWriter* profile_writer,
253 Zone* zone) const;
254 void Write(V8SnapshotProfileWriter* profile_writer,
255 JSONWriter* writer) const;
256 void WriteDebug(V8SnapshotProfileWriter* profile_writer,
257 JSONWriter* writer) const;
258
259 intptr_t offset() const { return offset_; }
260 void set_offset(intptr_t offset) {
261 ASSERT_EQUAL(offset_, -1);
262 offset_ = offset;
263 }
264
265 ObjectId id;
266 EdgeMap* edges = nullptr;
267 intptr_t type = kInvalidString;
268 intptr_t name = kInvalidString;
269 intptr_t self_size = 0;
270
271 private:
272 // Populated during serialization.
273 intptr_t offset_ = -1;
274 // 'trace_node_id' isn't supported.
275 // 'edge_count' is computed on-demand.
276 };
277
278 NodeInfo* EnsureId(const ObjectId& object_id);
279 void Write(JSONWriter* writer);
280
281 // Class that encapsulates both an array of strings and a mapping from
282 // strings to their index in the array.
283 class StringsTable {
284 public:
285 explicit StringsTable(Zone* zone)
286 : zone_(zone), index_map_(zone), strings_(zone, 2) {}
287
288 intptr_t Add(const char* str);
289 intptr_t AddFormatted(const char* fmt, ...) PRINTF_ATTRIBUTE(2, 3);
290 const char* At(intptr_t index) const;
291 void Write(JSONWriter* writer, const char* property = nullptr) const;
292
293 private:
294 Zone* zone_;
295 CStringIntMap index_map_;
296 GrowableArray<const char*> strings_;
297 };
298
299 struct ObjectIdToNodeInfoTraits {
300 typedef NodeInfo Pair;
301 typedef ObjectId Key;
302 typedef Pair Value;
303
304 static Key KeyOf(const Pair& pair) { return pair.id; }
305
306 static Value ValueOf(const Pair& pair) { return pair; }
307
308 static uword Hash(const Key& key) { return key.Hash(); }
309
310 static bool IsKeyEqual(const Pair& x, const Key& y) { return x.id == y; }
311 };
312
313 struct ObjectIdSetKeyValueTrait {
314 using Pair = ObjectId;
315 using Key = Pair;
316 using Value = Pair;
317
318 static Key KeyOf(const Pair& pair) { return pair; }
319 static Value ValueOf(const Pair& pair) { return pair; }
320 static uword Hash(const Key& key) { return key.Hash(); }
321 static bool IsKeyEqual(const Pair& pair, const Key& key) {
322 return pair == key;
323 }
324 };
325
326 Zone* const zone_;
327 DirectChainedHashMap<ObjectIdToNodeInfoTraits> nodes_;
328 StringsTable node_types_;
329 StringsTable edge_types_;
330 StringsTable strings_;
331 DirectChainedHashMap<ObjectIdSetKeyValueTrait> roots_;
332#endif
333};
334
335} // namespace dart
336
337#endif // RUNTIME_VM_V8_SNAPSHOT_WRITER_H_
TArray< uint32_t > Key
@ kInvalid
bool operator!=(const sk_sp< T > &a, const sk_sp< U > &b)
Definition SkRefCnt.h:355
std::map< Edge, int > EdgeMap
#define ASSERT_EQUAL(expected, actual)
Definition assert.h:309
static bool IsInt(intptr_t N, T value)
Definition utils.h:298
static uint32_t WordHash(intptr_t key)
Definition utils.cc:217
static constexpr size_t BitLength(int64_t value)
Definition utils.h:198
static const ObjectId kArtificialRootId
void AttributeReferenceTo(const ObjectId &from_object_id, const Reference &reference, const ObjectId &to_object_id)
void SetObjectTypeAndName(const ObjectId &object_id, const char *type, const char *name)
void AddRoot(const ObjectId &object_id, const char *name=nullptr)
void AttributeBytesTo(const ObjectId &object_id, size_t num_bytes)
bool HasId(const ObjectId &object_id)
void AttributeWeakReferenceTo(const ObjectId &from_object_id, const Reference &reference, const ObjectId &to_object_id, const ObjectId &replacement_object_id)
bool operator==(const FlutterPoint &a, const FlutterPoint &b)
#define ASSERT(E)
uint8_t value
uint32_t * target
const char * name
Definition fuchsia.cc:50
double y
double x
const char *const name
uint32_t CombineHashes(uint32_t hash, uint32_t other_hash)
Definition hash.h:12
uintptr_t uword
Definition globals.h:501
uint32_t FinalizeHash(uint32_t hash, intptr_t hashbits=kBitsPerInt32)
Definition hash.h:20
constexpr intptr_t kBitsPerInt64
Definition globals.h:467
static SkString fmt(SkColor4f c)
Definition p3.cpp:43
#define PRINTF_ATTRIBUTE(string_index, first_to_check)
Definition globals.h:697
Point offset
static constexpr Value kNoValue
Definition hash_map.h:463
void WriteDebug(JSONWriter *writer, const char *property=nullptr) const
void Write(JSONWriter *writer, const char *property=nullptr) const
ObjectId(IdSpace space, int64_t nonce)
bool operator==(const ObjectId &other) const
const char * ToCString(Zone *zone) const
bool operator!=(const ObjectId &other) const
static Reference Element(intptr_t offset)
static Reference Property(const char *name)
enum dart::V8SnapshotProfileWriter::Reference::Type type
const uintptr_t id