| // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #ifndef RUNTIME_VM_APP_SNAPSHOT_H_ |
| #define RUNTIME_VM_APP_SNAPSHOT_H_ |
| |
| #include "platform/assert.h" |
| #include "vm/allocation.h" |
| #include "vm/bitfield.h" |
| #include "vm/datastream.h" |
| #include "vm/globals.h" |
| #include "vm/growable_array.h" |
| #include "vm/hash_map.h" |
| #include "vm/object.h" |
| #include "vm/snapshot.h" |
| |
| namespace dart { |
| |
| // For full snapshots, we use a clustered snapshot format that trades longer |
| // serialization time for faster deserialization time and smaller snapshots. |
| // Objects are clustered by class to allow writing type information once per |
| // class instead once per object, and to allow filling the objects in a tight |
| // loop. The snapshot has two major sections: the first describes how to |
| // allocate the objects and the second describes how to initialize them. |
| // Deserialization starts by allocating a reference array large enough to hold |
| // the base objects (objects already available to both the serializer and |
| // deserializer) and the objects written in the snapshot. The allocation section |
| // is then read for each cluster, filling the reference array. Then the |
| // initialization/fill secton is read for each cluster, using the indices into |
| // the reference array to fill pointers. At this point, every object has been |
| // touched exactly once and in order, making this approach very cache friendly. |
| // Finally, each cluster is given an opportunity to perform some fix-ups that |
| // require the graph has been fully loaded, such as rehashing, though most |
| // clusters do not require fixups. |
| |
| // Forward declarations. |
| class V8SnapshotProfileWriter; |
| class ImageWriter; |
| class Heap; |
| |
| class LoadingUnitSerializationData : public ZoneAllocated { |
| public: |
| LoadingUnitSerializationData(intptr_t id, |
| LoadingUnitSerializationData* parent) |
| : id_(id), parent_(parent), deferred_objects_(), objects_(nullptr) {} |
| |
| intptr_t id() const { return id_; } |
| LoadingUnitSerializationData* parent() const { return parent_; } |
| void AddDeferredObject(CodePtr obj) { |
| deferred_objects_.Add(&Code::ZoneHandle(obj)); |
| } |
| GrowableArray<Code*>* deferred_objects() { return &deferred_objects_; } |
| ZoneGrowableArray<Object*>* objects() { |
| ASSERT(objects_ != nullptr); |
| return objects_; |
| } |
| void set_objects(ZoneGrowableArray<Object*>* objects) { |
| ASSERT(objects_ == nullptr); |
| objects_ = objects; |
| } |
| |
| private: |
| intptr_t id_; |
| LoadingUnitSerializationData* parent_; |
| GrowableArray<Code*> deferred_objects_; |
| ZoneGrowableArray<Object*>* objects_; |
| }; |
| |
| // This class can be used to read version and features from a snapshot before |
| // the VM has been initialized. |
| class SnapshotHeaderReader { |
| public: |
| static char* InitializeGlobalVMFlagsFromSnapshot(const Snapshot* snapshot); |
| |
| explicit SnapshotHeaderReader(const Snapshot* snapshot) |
| : SnapshotHeaderReader(snapshot->kind(), |
| snapshot->Addr(), |
| snapshot->length()) {} |
| |
| SnapshotHeaderReader(Snapshot::Kind kind, |
| const uint8_t* buffer, |
| intptr_t size) |
| : kind_(kind), stream_(buffer, size) { |
| stream_.SetPosition(Snapshot::kHeaderSize); |
| } |
| |
| void SetCoverageFromSnapshotFeatures(IsolateGroup* isolate_group); |
| |
| // Verifies the version and features in the snapshot are compatible with the |
| // current VM. If isolate is non-null it validates isolate-specific features. |
| // |
| // Returns null on success and a malloc()ed error on failure. |
| // The [offset] will be the next position in the snapshot stream after the |
| // features. |
| char* VerifyVersionAndFeatures(IsolateGroup* isolate_group, intptr_t* offset); |
| |
| private: |
| char* VerifyVersion(); |
| char* ReadFeatures(const char** features, intptr_t* features_length); |
| char* VerifyFeatures(IsolateGroup* isolate_group); |
| char* BuildError(const char* message); |
| |
| Snapshot::Kind kind_; |
| ReadStream stream_; |
| }; |
| |
| class FullSnapshotWriter { |
| public: |
| static constexpr intptr_t kInitialSize = 64 * KB; |
| FullSnapshotWriter(Snapshot::Kind kind, |
| NonStreamingWriteStream* vm_snapshot_data, |
| NonStreamingWriteStream* isolate_snapshot_data, |
| ImageWriter* vm_image_writer, |
| ImageWriter* iso_image_writer); |
| ~FullSnapshotWriter(); |
| |
| // Writes a full snapshot of the program(VM isolate, regular isolate group). |
| void WriteFullSnapshot( |
| GrowableArray<LoadingUnitSerializationData*>* data = nullptr); |
| void WriteUnitSnapshot(GrowableArray<LoadingUnitSerializationData*>* units, |
| LoadingUnitSerializationData* unit, |
| uint32_t program_hash); |
| |
| intptr_t VmIsolateSnapshotSize() const { return vm_isolate_snapshot_size_; } |
| intptr_t IsolateSnapshotSize() const { return isolate_snapshot_size_; } |
| |
| private: |
| Thread* thread() const { return thread_; } |
| Zone* zone() const { return thread_->zone(); } |
| IsolateGroup* isolate_group() const { return thread_->isolate_group(); } |
| Heap* heap() const { return isolate_group()->heap(); } |
| |
| // Writes a snapshot of the VM Isolate. |
| ZoneGrowableArray<Object*>* WriteVMSnapshot(); |
| |
| // Writes a full snapshot of regular Dart isolate group. |
| void WriteProgramSnapshot(ZoneGrowableArray<Object*>* objects, |
| GrowableArray<LoadingUnitSerializationData*>* data); |
| |
| Thread* thread_; |
| Snapshot::Kind kind_; |
| NonStreamingWriteStream* const vm_snapshot_data_; |
| NonStreamingWriteStream* const isolate_snapshot_data_; |
| intptr_t vm_isolate_snapshot_size_; |
| intptr_t isolate_snapshot_size_; |
| ImageWriter* vm_image_writer_; |
| ImageWriter* isolate_image_writer_; |
| |
| // Stats for benchmarking. |
| intptr_t clustered_vm_size_ = 0; |
| intptr_t clustered_isolate_size_ = 0; |
| intptr_t mapped_data_size_ = 0; |
| intptr_t mapped_text_size_ = 0; |
| intptr_t heap_vm_size_ = 0; |
| intptr_t heap_isolate_size_ = 0; |
| |
| V8SnapshotProfileWriter* profile_writer_ = nullptr; |
| |
| DISALLOW_COPY_AND_ASSIGN(FullSnapshotWriter); |
| }; |
| |
| class FullSnapshotReader { |
| public: |
| FullSnapshotReader(const Snapshot* snapshot, |
| const uint8_t* instructions_buffer, |
| Thread* thread); |
| ~FullSnapshotReader() {} |
| |
| ApiErrorPtr ReadVMSnapshot(); |
| ApiErrorPtr ReadProgramSnapshot(); |
| ApiErrorPtr ReadUnitSnapshot(const LoadingUnit& unit); |
| |
| private: |
| IsolateGroup* isolate_group() const { return thread_->isolate_group(); } |
| |
| ApiErrorPtr ConvertToApiError(char* message); |
| void InitializeBSS(); |
| |
| Snapshot::Kind kind_; |
| Thread* thread_; |
| const uint8_t* buffer_; |
| intptr_t size_; |
| const uint8_t* data_image_; |
| const uint8_t* instructions_image_; |
| |
| DISALLOW_COPY_AND_ASSIGN(FullSnapshotReader); |
| }; |
| |
| } // namespace dart |
| |
| #endif // RUNTIME_VM_APP_SNAPSHOT_H_ |