Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(426)

Side by Side Diff: runtime/vm/clustered_snapshot.h

Issue 2032153003: Use clustered serialization for full snapshots. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: round1 Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2016, 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 VM_CLUSTERED_SNAPSHOT_H_
6 #define VM_CLUSTERED_SNAPSHOT_H_
7
8 #include "platform/assert.h"
9 #include "vm/allocation.h"
10 #include "vm/bitfield.h"
11 #include "vm/datastream.h"
12 #include "vm/exceptions.h"
13 #include "vm/globals.h"
14 #include "vm/growable_array.h"
15 #include "vm/heap.h"
16 #include "vm/isolate.h"
17 #include "vm/object.h"
18 #include "vm/snapshot.h"
19 #include "vm/version.h"
20 #include "vm/visitor.h"
21
22 namespace dart {
23
24 // Forward declarations.
25 class Serializer;
26 class Deserializer;
27 class ObjectStore;
28
29 // For full snapshots, we use a clustered snapshot format that trades longer
30 // serialization time for faster deserialization time and smaller snapshots.
31 // Objects are clustered by class to allow writing type information once per
32 // class instead once per object, and to allow filling the objects in a tight
33 // loop. The snapshot has two major sections: the first describes how to
34 // allocate the objects and the second describes how to initialize them.
35 // Deserialization starts by allocating a reference array large enough to hold
36 // the base objects (objects already available to both the serializer and
37 // deserializer) and the objects written in the snapshot. The allocation section
38 // is then read for each cluster, filling the reference array. Then the
39 // initialization/fill secton is read for each cluster, using the indices into
40 // the reference array to fill pointers. At this point, every object has been
41 // touched exactly once and in order, making this approach very cache friendly.
42 // Finally, each cluster is given an opportunity to perform some fix-ups that
43 // require the graph has been fully loaded, such as rehashing, though most
44 // clusters do not require fixups.
45
46 class SerializationCluster : public ZoneAllocated {
47 public:
48 virtual ~SerializationCluster() { }
49
50 // Add [object] to the cluster and push its outgoing references.
51 virtual void Trace(Serializer* serializer, RawObject* object) = 0;
52
53 // Write the cluster type and information needed to allocate the cluster's
54 // objects. For fixed sized objects, this is just the object count. For
55 // variable sized objects, this is the object count and length of each object.
56 virtual void WriteAlloc(Serializer* serializer) = 0;
57
58 // Write the byte and reference data of the cluster's objects.
59 virtual void WriteFill(Serializer* serializer) = 0;
60 };
61
62
63 class DeserializationCluster : public ZoneAllocated {
64 public:
65 DeserializationCluster() : start_index_(-1), stop_index_(-1) { }
66 virtual ~DeserializationCluster() { }
67
68 // Allocate memory for all objects in the cluster and write their addresses
69 // into the ref array. Do not touch this memory.
70 virtual void ReadAlloc(Deserializer* deserializer) = 0;
71
72 // Initialize the cluster's objects. Do not touch the memory of other objects.
73 virtual void ReadFill(Deserializer* deserializer) = 0;
74
75 // Complete any action that requires the full graph to be deserialized, such
76 // as rehashing.
77 virtual void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) { }
78
79 protected:
80 // The range of the ref array that belongs to this cluster.
81 intptr_t start_index_;
82 intptr_t stop_index_;
83 };
84
85
86 class Serializer : public StackResource {
87 public:
88 Serializer(Thread* thread,
89 Snapshot::Kind kind,
90 uint8_t** buffer,
91 ReAlloc alloc,
92 intptr_t initial_size,
93 InstructionsWriter* instructions_writer_);
94 ~Serializer();
95
96 intptr_t WriteVMSnapshot(const Array& symbols, const Array& scripts);
97 void WriteFullSnapshot(intptr_t num_base_objects, ObjectStore* object_store);
98
99 void AddVMIsolateBaseObjects();
100
101 void AddBaseObject(RawObject* base_object) {
102 AssignRefNotTraced(base_object);
103 num_base_objects_++;
104 }
105
106 void AssignRefNotTraced(RawObject* object) {
107 ASSERT(next_ref_index_ != 0);
siva 2016/06/30 00:06:08 ASSERT(heap_->GetObjectId(object) == 0);
108 heap_->SetObjectId(object, next_ref_index_);
109 ASSERT(heap_->GetObjectId(object) == next_ref_index_);
110 next_ref_index_++;
111 }
112
113 void AssignRef(RawObject* object) {
114 ASSERT(next_ref_index_ != 0);
115 ASSERT(heap_->GetObjectId(object) == 1);
siva 2016/06/30 00:06:08 how do you end up with an initial id of 1?
rmacnak 2016/06/30 01:39:21 The 1 is a mark set by Push()
116 heap_->SetObjectId(object, next_ref_index_);
117 ASSERT(heap_->GetObjectId(object) == next_ref_index_);
118 next_ref_index_++;
siva 2016/06/30 00:06:08 AssignRef and AssignRefNotTraced seem to be identi
rmacnak 2016/06/30 01:39:21 Merged.
119 }
120
121 void Push(RawObject* object) {
122 if (!object->IsHeapObject()) {
123 return;
124 }
125
126 if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
127 return; // Do not trace, will write null.
128 }
129
130 if (object->IsSendPort()) {
131 // TODO(rmacnak): Do a better job of resetting fields in precompilation
132 // and assert this is unreachable.
133 return; // Do not trace, will write null.
134 }
135
136 intptr_t id = heap_->GetObjectId(object);
137 if (id == 0) {
138 heap_->SetObjectId(object, 1);
139 ASSERT(heap_->GetObjectId(object) != 0);
140 stack_.Add(object);
141 num_written_objects_++;
142 }
143 }
144
145 void AddUntracedRef() {
146 num_written_objects_++;
147 }
148
149 void Trace(RawObject* object);
150
151 SerializationCluster* NewClusterForClass(intptr_t cid);
152
153 void ReserveHeader() {
154 // Make room for recording snapshot buffer size.
155 stream_.set_current(stream_.buffer() + Snapshot::kHeaderSize);
156 }
157
158 void FillHeader(Snapshot::Kind kind) {
159 int64_t* data = reinterpret_cast<int64_t*>(stream_.buffer());
160 data[Snapshot::kLengthIndex] = stream_.bytes_written();
161 data[Snapshot::kSnapshotFlagIndex] = kind;
162 }
163
164 void WriteVersionAndFeatures();
165
166 void Serialize();
167 intptr_t bytes_written() { return stream_.bytes_written(); }
168
169 // Writes raw data to the stream (basic type).
170 // sizeof(T) must be in {1,2,4,8}.
171 template <typename T>
172 void Write(T value) {
173 WriteStream::Raw<sizeof(T), T>::Write(&stream_, value);
174 }
175
176 void WriteBytes(const uint8_t* addr, intptr_t len) {
177 stream_.WriteBytes(addr, len);
178 }
179
180 void WriteRef(RawObject* object) {
181 if (!object->IsHeapObject()) {
182 Write<intptr_t>(reinterpret_cast<intptr_t>(object));
183 return;
184 }
185
186 intptr_t id = heap_->GetObjectId(object);
187 if (id == 0) {
188 if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
189 WriteRef(Object::null());
190 return;
191 }
192 if (object->IsSendPort()) {
193 // TODO(rmacnak): Do a better job of resetting fields in precompilation
194 // and assert this is unreachable.
195 WriteRef(Object::null());
196 return;
197 }
198 FATAL("Missing ref");
199 }
200 Write<intptr_t>((id << 1) | 1);
siva 2016/06/30 00:06:08 We should probably use an enum instead of 1, somet
rmacnak 2016/06/30 01:39:21 Done.
201 }
202
203 void WriteTokenPosition(TokenPosition pos) {
204 Write<int32_t>(pos.SnapshotEncode());
205 }
206
207 void WriteCid(intptr_t cid) {
siva 2016/06/30 00:06:08 COMPILE_ASSERT(RawObject::kClassIdTagSize == 32);
rmacnak 2016/06/30 01:39:21 <= 32
208 Write<int32_t>(cid);
209 }
210
211 int32_t GetTextOffset(RawInstructions* instr, RawCode* code) {
212 return instructions_writer_->GetOffsetFor(instr, code);
213 }
214
215 int32_t GetRODataOffset(RawObject* object) {
216 return instructions_writer_->GetObjectOffsetFor(object);
217 }
218
219 Snapshot::Kind kind() const { return kind_; }
220
221 private:
222 Heap* heap_;
223 Zone* zone_;
224 Snapshot::Kind kind_;
225 WriteStream stream_;
226 InstructionsWriter* instructions_writer_;
227 SerializationCluster** clusters_by_cid_;
228 GrowableArray<RawObject*> stack_;
229 intptr_t num_cids_;
230 intptr_t num_base_objects_;
231 intptr_t num_written_objects_;
232 intptr_t next_ref_index_;
233
234 DISALLOW_IMPLICIT_CONSTRUCTORS(Serializer);
235 };
236
237
238 class Deserializer : public StackResource {
239 public:
240 Deserializer(Thread* thread,
241 Snapshot::Kind kind,
242 const uint8_t* buffer,
243 intptr_t size,
244 const uint8_t* instructions_buffer,
245 const uint8_t* data_buffer);
246 ~Deserializer();
247
248 void ReadFullSnapshot(ObjectStore* object_store);
249 void ReadVMSnapshot();
250
251 void AddVMIsolateBaseObjects();
252
253 static void InitializeHeader(RawObject* raw,
254 intptr_t cid,
255 intptr_t size,
256 bool is_vm_isolate,
257 bool is_canonical = false);
258
259 // Reads raw data (for basic types).
260 // sizeof(T) must be in {1,2,4,8}.
261 template <typename T>
262 T Read() {
263 return ReadStream::Raw<sizeof(T), T>::Read(&stream_);
264 }
265
266 void ReadBytes(uint8_t* addr, intptr_t len) {
267 stream_.ReadBytes(addr, len);
268 }
269
270 const uint8_t* CurrentBufferAddress() const {
271 return stream_.AddressOfCurrentPosition();
272 }
273
274 void Advance(intptr_t value) {
275 stream_.Advance(value);
276 }
277
278 intptr_t PendingBytes() const {
279 return stream_.PendingBytes();
280 }
281
282 void AddBaseObject(RawObject* base_object) {
283 AssignRef(base_object);
284 }
285
286 void AssignRef(RawObject* object) {
287 ASSERT(next_ref_index_ <= num_objects_);
288 refs_->ptr()->data()[next_ref_index_] = object;
289 next_ref_index_++;
290 }
291
292 RawObject* Ref(intptr_t index) const {
293 ASSERT(index > 0);
294 ASSERT(index <= num_objects_);
295 return refs_->ptr()->data()[index];
296 }
297
298 RawObject* ReadRef() {
299 intptr_t index = Read<intptr_t>();
300 if ((index & 1) == 0) {
301 return reinterpret_cast<RawSmi*>(index);
302 }
303 return Ref(index >> 1);
304 }
305
306 TokenPosition ReadTokenPosition() {
307 return TokenPosition::SnapshotDecode(Read<int32_t>());
308 }
309
310 intptr_t ReadCid() {
siva 2016/06/30 00:06:08 Ditto COMPILE_ASSERT....
rmacnak 2016/06/30 01:39:22 <= 32
311 return Read<int32_t>();
312 }
313
314 uword GetInstructionsAt(int32_t offset) {
315 return instructions_reader_->GetInstructionsAt(offset);
316 }
317
318 RawObject* GetObjectAt(int32_t offset) {
319 return instructions_reader_->GetObjectAt(offset);
320 }
321
322 RawApiError* VerifyVersionAndFeatures();
323
324 void Prepare();
325 void Deserialize();
326
327 DeserializationCluster* ReadCluster();
328
329 intptr_t next_index() const { return next_ref_index_; }
330 Heap* heap() const { return heap_; }
331 Snapshot::Kind kind() const { return kind_; }
332
333 private:
334 Heap* heap_;
335 Zone* zone_;
336 Snapshot::Kind kind_;
337 ReadStream stream_;
338 InstructionsReader* instructions_reader_;
339 intptr_t num_objects_;
340 intptr_t num_clusters_;
341 RawArray* refs_;
342 intptr_t next_ref_index_;
343 DeserializationCluster** clusters_;
344 };
345
346
347 class FullSnapshotWriter {
348 public:
349 static const intptr_t kInitialSize = 64 * KB;
350 FullSnapshotWriter(Snapshot::Kind kind,
351 uint8_t** vm_isolate_snapshot_buffer,
352 uint8_t** isolate_snapshot_buffer,
353 ReAlloc alloc,
354 InstructionsWriter* instructions_writer);
355 ~FullSnapshotWriter();
356
357 uint8_t** vm_isolate_snapshot_buffer() {
siva 2016/06/30 00:06:08 const {
rmacnak 2016/06/30 01:39:21 Done.
358 return vm_isolate_snapshot_buffer_;
359 }
360
361 uint8_t** isolate_snapshot_buffer() {
siva 2016/06/30 00:06:08 const
rmacnak 2016/06/30 01:39:21 Done.
362 return isolate_snapshot_buffer_;
363 }
364
365 Thread* thread() const { return thread_; }
366 Zone* zone() const { return thread_->zone(); }
367 Isolate* isolate() const { return thread_->isolate(); }
368 Heap* heap() const { return isolate()->heap(); }
369
370 // Writes a full snapshot of the Isolate.
371 void WriteFullSnapshot();
372
373 intptr_t VmIsolateSnapshotSize() const {
374 return vm_isolate_snapshot_size_;
375 }
376 intptr_t IsolateSnapshotSize() const {
377 return isolate_snapshot_size_;
378 }
379
380 private:
381 // Writes a snapshot of the VM Isolate.
382 intptr_t WriteVmIsolateSnapshot();
383
384 // Writes a full snapshot of a regular Dart Isolate.
385 void WriteIsolateFullSnapshot(intptr_t num_base_objects);
386
387 Thread* thread_;
388 Snapshot::Kind kind_;
389 uint8_t** vm_isolate_snapshot_buffer_;
390 uint8_t** isolate_snapshot_buffer_;
391 ReAlloc alloc_;
392 intptr_t vm_isolate_snapshot_size_;
393 intptr_t isolate_snapshot_size_;
394 ForwardList* forward_list_;
395 InstructionsWriter* instructions_writer_;
396 Array& scripts_;
397 Array& saved_symbol_table_;
398 Array& new_vm_symbol_table_;
399
400 DISALLOW_COPY_AND_ASSIGN(FullSnapshotWriter);
401 };
402
403
404 class VmIsolateSnapshotReader {
405 public:
406 VmIsolateSnapshotReader(Snapshot::Kind kind,
407 const uint8_t* buffer,
408 intptr_t size,
409 const uint8_t* instructions_buffer,
410 const uint8_t* data_buffer,
411 Thread* thread) :
412 kind_(kind),
413 thread_(thread),
414 buffer_(buffer),
415 size_(size),
416 instructions_buffer_(instructions_buffer),
417 data_buffer_(data_buffer) {
418 thread->isolate()->set_compilation_allowed(kind != Snapshot::kAppNoJIT);
419 }
420
421 ~VmIsolateSnapshotReader() { }
422
423 RawApiError* ReadVmIsolateSnapshot();
424
425 private:
426 Snapshot::Kind kind_;
427 Thread* thread_;
428 const uint8_t* buffer_;
429 intptr_t size_;
430 const uint8_t* instructions_buffer_;
431 const uint8_t* data_buffer_;
432
433 DISALLOW_COPY_AND_ASSIGN(VmIsolateSnapshotReader);
434 };
435
436
437 class IsolateSnapshotReader {
438 public:
439 IsolateSnapshotReader(Snapshot::Kind kind,
440 const uint8_t* buffer,
441 intptr_t size,
442 const uint8_t* instructions_buffer,
443 const uint8_t* data_buffer,
444 Thread* thread) :
siva 2016/06/30 00:06:08 formatting seems odd.
rmacnak 2016/06/30 01:39:21 Fixed. (was due to renaming)
445 kind_(kind),
446 thread_(thread),
447 buffer_(buffer),
448 size_(size),
449 instructions_buffer_(instructions_buffer),
450 data_buffer_(data_buffer) {
451 thread->isolate()->set_compilation_allowed(kind != Snapshot::kAppNoJIT);
452 }
453
454 ~IsolateSnapshotReader() {}
455
456 RawApiError* ReadFullSnapshot();
457
458 private:
459 Snapshot::Kind kind_;
460 Thread* thread_;
461 const uint8_t* buffer_;
462 intptr_t size_;
463 const uint8_t* instructions_buffer_;
464 const uint8_t* data_buffer_;
465
466 DISALLOW_COPY_AND_ASSIGN(IsolateSnapshotReader);
467 };
468
469 } // namespace dart
470
471 #endif // VM_CLUSTERED_SNAPSHOT_H_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698