OLD | NEW |
---|---|
(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_ | |
OLD | NEW |