Files
sdk/runtime/vm/app_snapshot.h
Ryan Macnak d36adbacaf [vm] Remove the VM isolate.
The former contents of the VM isolate are now included into each isolate group. This makes each isolate group's heap independent, and in particular allows each heap to be allocated to a separate pointer cage (not done in this CL).

The duplicated stubs that allowed PC relative calls are removed, since the originals can now be the target of PC relative calls.

The bootstrapping needing to load an AppJIT or AppAOT snapshot is reduced to allocating the oddballs. The code is entirely dropped in the AOT runtime, but the JIT runtime still has it to allow for flags to affect the compilation of the stub code. Further refactoring might be able to remove this for the JIT runtime too, with only gen_snapshot knowing how to bootstrap.

Class serialization no longer distinguishes predefined classes.

The page containing null is marked as never-evacuate. null, false and true must not move because the compiler relies on their low bits having certain patterns for some optimizations. (Previously, the entire VM isolate heap never moved.)

Compaction is disabled for IA32. Due to register pressure, some stub calls must not use a scratch register and embed the address of Code.

The page containing the call-through-safepoint stub is frozen when running with --write-protect-code and the stub is created at runtime (instead of loaded from an AppJIT or AppAOT snapshot). This stub must remain executable even during a safepoint, as a foreign call might during return during a safepoint and only block after the stub directs it to the runtime.

The snapshot symbols are renamed to kDartSnapshotData and kDartSnapshotText. There is no need to distinguish the VM isolate's snapshot, and snaphots are per isolate group not per isolate. Aliases with the old names are added to ease migration.

Some global flags that were automatically set based on the VM isolate's snapshot are now isolate group flags and automatically set by the isolate group's snapshot.

TEST=ci
Change-Id: Iee82016057d609112e9b021d178fc3d4d18b5044
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/500621
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Tess Strickland <sstrickl@google.com>
SLSA-Policy-Verified: SLSA Policy Verification Service <devtools-gerritcodereview-exitgate@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
2026-05-18 11:35:03 -07:00

180 lines
6.2 KiB
C++

// 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 ZoneObject {
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* InitializeIsolateGroupFlagsFromSnapshot(
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);
}
// 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 = 2 * MB;
FullSnapshotWriter(Snapshot::Kind kind,
NonStreamingWriteStream* snapshot_data,
ImageWriter* image_writer);
~FullSnapshotWriter();
// Writes a full snapshot of the program.
void WriteFullSnapshot(
GrowableArray<LoadingUnitSerializationData*>* data = nullptr);
// Writes a snapshot for a deferred loading unit.
void WriteUnitSnapshot(GrowableArray<LoadingUnitSerializationData*>* units,
LoadingUnitSerializationData* unit,
uint32_t program_hash);
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 full snapshot of regular Dart isolate group.
void WriteProgramSnapshot(GrowableArray<LoadingUnitSerializationData*>* data);
Thread* thread_;
Snapshot::Kind kind_;
NonStreamingWriteStream* const snapshot_data_;
ImageWriter* 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() {}
// On success, returns nullptr. On failure, returns an error message that the
// caller must free.
char* ReadProgramSnapshot();
char* ReadUnitSnapshot(const LoadingUnit& unit);
private:
IsolateGroup* isolate_group() const { return thread_->isolate_group(); }
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_