7 #include "src/snapshot/snapshot.h" 9 #include "src/base/platform/platform.h" 10 #include "src/snapshot/partial-deserializer.h" 11 #include "src/snapshot/startup-deserializer.h" 12 #include "src/version.h" 18 bool Snapshot::SnapshotIsValid(
const v8::StartupData* snapshot_blob) {
19 return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
23 bool Snapshot::HasContextSnapshot(Isolate* isolate,
size_t index) {
25 const v8::StartupData* blob = isolate->snapshot_blob();
26 if (blob ==
nullptr)
return false;
27 if (blob->data ==
nullptr)
return false;
28 size_t num_contexts =
static_cast<size_t>(ExtractNumContexts(blob));
29 return index < num_contexts;
32 bool Snapshot::Initialize(Isolate* isolate) {
33 if (!isolate->snapshot_available())
return false;
34 base::ElapsedTimer timer;
35 if (FLAG_profile_deserialization) timer.Start();
37 const v8::StartupData* blob = isolate->snapshot_blob();
39 CHECK(VerifyChecksum(blob));
40 Vector<const byte> startup_data = ExtractStartupData(blob);
41 SnapshotData startup_snapshot_data(startup_data);
42 Vector<const byte> read_only_data = ExtractReadOnlyData(blob);
43 SnapshotData read_only_snapshot_data(read_only_data);
44 StartupDeserializer deserializer(&startup_snapshot_data,
45 &read_only_snapshot_data);
46 deserializer.SetRehashability(ExtractRehashability(blob));
47 bool success = isolate->Init(&deserializer);
48 if (FLAG_profile_deserialization) {
49 double ms = timer.Elapsed().InMillisecondsF();
50 int bytes = startup_data.length();
51 PrintF(
"[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
56 MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
57 Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
size_t context_index,
58 v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
59 if (!isolate->snapshot_available())
return Handle<Context>();
60 base::ElapsedTimer timer;
61 if (FLAG_profile_deserialization) timer.Start();
63 const v8::StartupData* blob = isolate->snapshot_blob();
64 bool can_rehash = ExtractRehashability(blob);
65 Vector<const byte> context_data =
66 ExtractContextData(blob, static_cast<uint32_t>(context_index));
67 SnapshotData snapshot_data(context_data);
69 MaybeHandle<Context> maybe_result = PartialDeserializer::DeserializeContext(
70 isolate, &snapshot_data, can_rehash, global_proxy,
71 embedder_fields_deserializer);
73 Handle<Context> result;
74 if (!maybe_result.ToHandle(&result))
return MaybeHandle<Context>();
76 if (FLAG_profile_deserialization) {
77 double ms = timer.Elapsed().InMillisecondsF();
78 int bytes = context_data.length();
79 PrintF(
"[Deserializing context #%zu (%d bytes) took %0.3f ms]\n",
80 context_index, bytes, ms);
85 void ProfileDeserialization(
86 const SnapshotData* read_only_snapshot,
87 const SnapshotData* startup_snapshot,
88 const std::vector<SnapshotData*>& context_snapshots) {
89 if (FLAG_profile_deserialization) {
90 int startup_total = 0;
91 PrintF(
"Deserialization will reserve:\n");
92 for (
const auto& reservation : read_only_snapshot->Reservations()) {
93 startup_total += reservation.chunk_size();
95 for (
const auto& reservation : startup_snapshot->Reservations()) {
96 startup_total += reservation.chunk_size();
98 PrintF(
"%10d bytes per isolate\n", startup_total);
99 for (
size_t i = 0;
i < context_snapshots.size();
i++) {
100 int context_total = 0;
101 for (
const auto& reservation : context_snapshots[
i]->Reservations()) {
102 context_total += reservation.chunk_size();
104 PrintF(
"%10d bytes per context #%zu\n", context_total,
i);
109 v8::StartupData Snapshot::CreateSnapshotBlob(
110 const SnapshotData* startup_snapshot,
111 const SnapshotData* read_only_snapshot,
112 const std::vector<SnapshotData*>& context_snapshots,
bool can_be_rehashed) {
114 uint32_t startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
115 uint32_t total_length = startup_snapshot_offset;
116 DCHECK(IsAligned(total_length, kPointerAlignment));
117 total_length +=
static_cast<uint32_t>(startup_snapshot->RawData().length());
118 DCHECK(IsAligned(total_length, kPointerAlignment));
119 total_length +=
static_cast<uint32_t>(read_only_snapshot->RawData().length());
120 DCHECK(IsAligned(total_length, kPointerAlignment));
121 for (
const auto context_snapshot : context_snapshots) {
122 total_length +=
static_cast<uint32_t>(context_snapshot->RawData().length());
123 DCHECK(IsAligned(total_length, kPointerAlignment));
126 ProfileDeserialization(read_only_snapshot, startup_snapshot,
129 char* data =
new char[total_length];
131 memset(data, 0, StartupSnapshotOffset(num_contexts));
133 SetHeaderValue(data, kNumberOfContextsOffset, num_contexts);
134 SetHeaderValue(data, kRehashabilityOffset, can_be_rehashed ? 1 : 0);
137 memset(data + kVersionStringOffset, 0, kVersionStringLength);
139 Vector<char>(data + kVersionStringOffset, kVersionStringLength));
142 uint32_t payload_offset = startup_snapshot_offset;
144 static_cast<uint32_t>(startup_snapshot->RawData().length());
145 CopyBytes(data + payload_offset,
146 reinterpret_cast<const char*>(startup_snapshot->RawData().start()),
148 if (FLAG_profile_deserialization) {
149 PrintF(
"Snapshot blob consists of:\n%10d bytes in %d chunks for startup\n",
151 static_cast<uint32_t>(startup_snapshot->Reservations().size()));
153 payload_offset += payload_length;
156 SetHeaderValue(data, kReadOnlyOffsetOffset, payload_offset);
157 payload_length = read_only_snapshot->RawData().length();
159 data + payload_offset,
160 reinterpret_cast<const char*>(read_only_snapshot->RawData().start()),
162 if (FLAG_profile_deserialization) {
163 PrintF(
"%10d bytes for read-only\n", payload_length);
165 payload_offset += payload_length;
169 SetHeaderValue(data, ContextSnapshotOffsetOffset(
i), payload_offset);
170 SnapshotData* context_snapshot = context_snapshots[
i];
171 payload_length = context_snapshot->RawData().length();
173 data + payload_offset,
174 reinterpret_cast<const char*>(context_snapshot->RawData().start()),
176 if (FLAG_profile_deserialization) {
177 PrintF(
"%10d bytes in %d chunks for context #%d\n", payload_length,
178 static_cast<uint32_t>(context_snapshot->Reservations().size()),
i);
180 payload_offset += payload_length;
183 DCHECK_EQ(total_length, payload_offset);
184 v8::StartupData result = {data,
static_cast<int>(total_length)};
186 Checksum checksum(ChecksummedContent(&result));
187 SetHeaderValue(data, kChecksumPartAOffset, checksum.a());
188 SetHeaderValue(data, kChecksumPartBOffset, checksum.b());
193 uint32_t Snapshot::ExtractNumContexts(
const v8::StartupData* data) {
194 CHECK_LT(kNumberOfContextsOffset, data->raw_size);
195 uint32_t num_contexts = GetHeaderValue(data, kNumberOfContextsOffset);
199 bool Snapshot::VerifyChecksum(
const v8::StartupData* data) {
200 base::ElapsedTimer timer;
201 if (FLAG_profile_deserialization) timer.Start();
202 uint32_t expected_a = GetHeaderValue(data, kChecksumPartAOffset);
203 uint32_t expected_b = GetHeaderValue(data, kChecksumPartBOffset);
204 Checksum checksum(ChecksummedContent(data));
205 if (FLAG_profile_deserialization) {
206 double ms = timer.Elapsed().InMillisecondsF();
207 PrintF(
"[Verifying snapshot checksum took %0.3f ms]\n", ms);
209 return checksum.Check(expected_a, expected_b);
212 uint32_t Snapshot::ExtractContextOffset(
const v8::StartupData* data,
217 GetHeaderValue(data, ContextSnapshotOffsetOffset(index));
218 CHECK_LT(context_offset, static_cast<uint32_t>(data->raw_size));
219 return context_offset;
222 bool Snapshot::ExtractRehashability(
const v8::StartupData* data) {
223 CHECK_LT(kRehashabilityOffset, static_cast<uint32_t>(data->raw_size));
224 return GetHeaderValue(data, kRehashabilityOffset) != 0;
228 Vector<const byte> ExtractData(
const v8::StartupData* snapshot,
230 CHECK_LT(start_offset, end_offset);
231 CHECK_LT(end_offset, snapshot->raw_size);
232 uint32_t length = end_offset - start_offset;
234 reinterpret_cast<const byte*
>(snapshot->data + start_offset);
235 return Vector<const byte>(data, length);
239 Vector<const byte> Snapshot::ExtractStartupData(
const v8::StartupData* data) {
240 DCHECK(SnapshotIsValid(data));
242 uint32_t num_contexts = ExtractNumContexts(data);
243 return ExtractData(data, StartupSnapshotOffset(num_contexts),
244 GetHeaderValue(data, kReadOnlyOffsetOffset));
247 Vector<const byte> Snapshot::ExtractReadOnlyData(
const v8::StartupData* data) {
248 DCHECK(SnapshotIsValid(data));
250 return ExtractData(data, GetHeaderValue(data, kReadOnlyOffsetOffset),
251 GetHeaderValue(data, ContextSnapshotOffsetOffset(0)));
254 Vector<const byte> Snapshot::ExtractContextData(
const v8::StartupData* data,
256 uint32_t num_contexts = ExtractNumContexts(data);
257 CHECK_LT(index, num_contexts);
259 uint32_t context_offset = ExtractContextOffset(data, index);
261 if (index == num_contexts - 1) {
262 next_context_offset = data->raw_size;
264 next_context_offset = ExtractContextOffset(data, index + 1);
265 CHECK_LT(next_context_offset, data->raw_size);
268 const byte* context_data =
269 reinterpret_cast<const byte*
>(data->data + context_offset);
270 uint32_t context_length = next_context_offset - context_offset;
271 return Vector<const byte>(context_data, context_length);
274 void Snapshot::CheckVersion(
const v8::StartupData* data) {
275 char version[kVersionStringLength];
276 memset(version, 0, kVersionStringLength);
277 CHECK_LT(kVersionStringOffset + kVersionStringLength,
278 static_cast<uint32_t>(data->raw_size));
279 Version::GetString(Vector<char>(version, kVersionStringLength));
280 if (strncmp(version, data->data + kVersionStringOffset,
281 kVersionStringLength) != 0) {
283 "Version mismatch between V8 binary and snapshot.\n" 284 "# V8 binary version: %.*s\n" 285 "# Snapshot version: %.*s\n" 286 "# The snapshot consists of %d bytes and contains %d context(s).",
287 kVersionStringLength, version, kVersionStringLength,
288 data->data + kVersionStringOffset, data->raw_size,
289 ExtractNumContexts(data));
293 SnapshotData::SnapshotData(
const Serializer* serializer) {
294 DisallowHeapAllocation no_gc;
295 std::vector<Reservation> reservations = serializer->EncodeReservations();
296 const std::vector<byte>* payload = serializer->Payload();
300 static_cast<uint32_t>(reservations.size()) * kUInt32Size;
301 uint32_t payload_offset = kHeaderSize + reservation_size;
302 uint32_t padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset);
304 padded_payload_offset +
static_cast<uint32_t>(payload->size());
305 DCHECK(IsAligned(size, kPointerAlignment));
311 memset(data_, 0, padded_payload_offset);
314 SetMagicNumber(serializer->isolate());
315 SetHeaderValue(kNumReservationsOffset, static_cast<int>(reservations.size()));
316 SetHeaderValue(kPayloadLengthOffset, static_cast<int>(payload->size()));
319 CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.data()),
323 CopyBytes(data_ + padded_payload_offset, payload->data(),
324 static_cast<size_t>(payload->size()));
327 std::vector<SerializedData::Reservation> SnapshotData::Reservations()
const {
328 uint32_t size = GetHeaderValue(kNumReservationsOffset);
329 std::vector<SerializedData::Reservation> reservations(size);
330 memcpy(reservations.data(), data_ + kHeaderSize,
331 size *
sizeof(SerializedData::Reservation));
335 Vector<const byte> SnapshotData::Payload()
const {
337 GetHeaderValue(kNumReservationsOffset) * kUInt32Size;
339 POINTER_SIZE_ALIGN(kHeaderSize + reservations_size);
340 const byte* payload = data_ + padded_payload_offset;
341 uint32_t length = GetHeaderValue(kPayloadLengthOffset);
342 DCHECK_EQ(data_ + size_, payload + length);
343 return Vector<const byte>(payload, length);