Line data Source code
1 : // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : // The common functionality when building with or without snapshots.
6 :
7 : #include "src/snapshot/snapshot.h"
8 :
9 : #include "src/base/platform/platform.h"
10 : #include "src/counters.h"
11 : #include "src/snapshot/partial-deserializer.h"
12 : #include "src/snapshot/startup-deserializer.h"
13 : #include "src/version.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : #ifdef DEBUG
19 : bool Snapshot::SnapshotIsValid(const v8::StartupData* snapshot_blob) {
20 : return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
21 : }
22 : #endif // DEBUG
23 :
24 45 : bool Snapshot::HasContextSnapshot(Isolate* isolate, size_t index) {
25 : // Do not use snapshots if the isolate is used to create snapshots.
26 : const v8::StartupData* blob = isolate->snapshot_blob();
27 45 : if (blob == nullptr) return false;
28 45 : if (blob->data == nullptr) return false;
29 45 : size_t num_contexts = static_cast<size_t>(ExtractNumContexts(blob));
30 45 : return index < num_contexts;
31 : }
32 :
33 121876 : bool Snapshot::Initialize(Isolate* isolate) {
34 60938 : if (!isolate->snapshot_available()) return false;
35 : RuntimeCallTimerScope rcs_timer(isolate,
36 60938 : RuntimeCallCounterId::kDeserializeIsolate);
37 : base::ElapsedTimer timer;
38 60938 : if (FLAG_profile_deserialization) timer.Start();
39 :
40 : const v8::StartupData* blob = isolate->snapshot_blob();
41 60938 : CheckVersion(blob);
42 60938 : CHECK(VerifyChecksum(blob));
43 60938 : Vector<const byte> startup_data = ExtractStartupData(blob);
44 : SnapshotData startup_snapshot_data(startup_data);
45 60938 : Vector<const byte> read_only_data = ExtractReadOnlyData(blob);
46 : SnapshotData read_only_snapshot_data(read_only_data);
47 : StartupDeserializer deserializer(&startup_snapshot_data,
48 : &read_only_snapshot_data);
49 60937 : deserializer.SetRehashability(ExtractRehashability(blob));
50 60938 : bool success = isolate->Init(&deserializer);
51 60938 : if (FLAG_profile_deserialization) {
52 5 : double ms = timer.Elapsed().InMillisecondsF();
53 : int bytes = startup_data.length();
54 5 : PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
55 : }
56 : return success;
57 : }
58 :
59 89731 : MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
60 179417 : Isolate* isolate, Handle<JSGlobalProxy> global_proxy, size_t context_index,
61 : v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
62 89731 : if (!isolate->snapshot_available()) return Handle<Context>();
63 : RuntimeCallTimerScope rcs_timer(isolate,
64 89686 : RuntimeCallCounterId::kDeserializeContext);
65 : base::ElapsedTimer timer;
66 89686 : if (FLAG_profile_deserialization) timer.Start();
67 :
68 : const v8::StartupData* blob = isolate->snapshot_blob();
69 89686 : bool can_rehash = ExtractRehashability(blob);
70 : Vector<const byte> context_data =
71 89686 : ExtractContextData(blob, static_cast<uint32_t>(context_index));
72 : SnapshotData snapshot_data(context_data);
73 :
74 : MaybeHandle<Context> maybe_result = PartialDeserializer::DeserializeContext(
75 : isolate, &snapshot_data, can_rehash, global_proxy,
76 89686 : embedder_fields_deserializer);
77 :
78 : Handle<Context> result;
79 89686 : if (!maybe_result.ToHandle(&result)) return MaybeHandle<Context>();
80 :
81 89686 : if (FLAG_profile_deserialization) {
82 5 : double ms = timer.Elapsed().InMillisecondsF();
83 : int bytes = context_data.length();
84 : PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n",
85 5 : context_index, bytes, ms);
86 : }
87 89686 : return result;
88 : }
89 :
90 191 : void ProfileDeserialization(
91 : const SnapshotData* read_only_snapshot,
92 : const SnapshotData* startup_snapshot,
93 10 : const std::vector<SnapshotData*>& context_snapshots) {
94 191 : if (FLAG_profile_deserialization) {
95 : int startup_total = 0;
96 5 : PrintF("Deserialization will reserve:\n");
97 45 : for (const auto& reservation : read_only_snapshot->Reservations()) {
98 30 : startup_total += reservation.chunk_size();
99 : }
100 45 : for (const auto& reservation : startup_snapshot->Reservations()) {
101 30 : startup_total += reservation.chunk_size();
102 : }
103 5 : PrintF("%10d bytes per isolate\n", startup_total);
104 20 : for (size_t i = 0; i < context_snapshots.size(); i++) {
105 : int context_total = 0;
106 170 : for (const auto& reservation : context_snapshots[i]->Reservations()) {
107 155 : context_total += reservation.chunk_size();
108 : }
109 5 : PrintF("%10d bytes per context #%zu\n", context_total, i);
110 : }
111 : }
112 191 : }
113 :
114 191 : v8::StartupData Snapshot::CreateSnapshotBlob(
115 382 : const SnapshotData* startup_snapshot,
116 382 : const SnapshotData* read_only_snapshot,
117 417 : const std::vector<SnapshotData*>& context_snapshots, bool can_be_rehashed) {
118 191 : uint32_t num_contexts = static_cast<uint32_t>(context_snapshots.size());
119 191 : uint32_t startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
120 : uint32_t total_length = startup_snapshot_offset;
121 : DCHECK(IsAligned(total_length, kPointerAlignment));
122 191 : total_length += static_cast<uint32_t>(startup_snapshot->RawData().length());
123 : DCHECK(IsAligned(total_length, kPointerAlignment));
124 191 : total_length += static_cast<uint32_t>(read_only_snapshot->RawData().length());
125 : DCHECK(IsAligned(total_length, kPointerAlignment));
126 608 : for (const auto context_snapshot : context_snapshots) {
127 226 : total_length += static_cast<uint32_t>(context_snapshot->RawData().length());
128 : DCHECK(IsAligned(total_length, kPointerAlignment));
129 : }
130 :
131 : ProfileDeserialization(read_only_snapshot, startup_snapshot,
132 191 : context_snapshots);
133 :
134 191 : char* data = new char[total_length];
135 : // Zero out pre-payload data. Part of that is only used for padding.
136 191 : memset(data, 0, StartupSnapshotOffset(num_contexts));
137 :
138 : SetHeaderValue(data, kNumberOfContextsOffset, num_contexts);
139 191 : SetHeaderValue(data, kRehashabilityOffset, can_be_rehashed ? 1 : 0);
140 :
141 : // Write version string into snapshot data.
142 191 : memset(data + kVersionStringOffset, 0, kVersionStringLength);
143 : Version::GetString(
144 191 : Vector<char>(data + kVersionStringOffset, kVersionStringLength));
145 :
146 : // Startup snapshot (isolate-specific data).
147 : uint32_t payload_offset = startup_snapshot_offset;
148 : uint32_t payload_length =
149 : static_cast<uint32_t>(startup_snapshot->RawData().length());
150 : CopyBytes(data + payload_offset,
151 : reinterpret_cast<const char*>(startup_snapshot->RawData().start()),
152 191 : payload_length);
153 191 : if (FLAG_profile_deserialization) {
154 : PrintF("Snapshot blob consists of:\n%10d bytes in %d chunks for startup\n",
155 : payload_length,
156 15 : static_cast<uint32_t>(startup_snapshot->Reservations().size()));
157 : }
158 191 : payload_offset += payload_length;
159 :
160 : // Read-only.
161 : SetHeaderValue(data, kReadOnlyOffsetOffset, payload_offset);
162 : payload_length = read_only_snapshot->RawData().length();
163 : CopyBytes(
164 : data + payload_offset,
165 : reinterpret_cast<const char*>(read_only_snapshot->RawData().start()),
166 191 : payload_length);
167 191 : if (FLAG_profile_deserialization) {
168 5 : PrintF("%10d bytes for read-only\n", payload_length);
169 : }
170 191 : payload_offset += payload_length;
171 :
172 : // Partial snapshots (context-specific data).
173 417 : for (uint32_t i = 0; i < num_contexts; i++) {
174 226 : SetHeaderValue(data, ContextSnapshotOffsetOffset(i), payload_offset);
175 452 : SnapshotData* context_snapshot = context_snapshots[i];
176 : payload_length = context_snapshot->RawData().length();
177 : CopyBytes(
178 : data + payload_offset,
179 : reinterpret_cast<const char*>(context_snapshot->RawData().start()),
180 226 : payload_length);
181 226 : if (FLAG_profile_deserialization) {
182 : PrintF("%10d bytes in %d chunks for context #%d\n", payload_length,
183 15 : static_cast<uint32_t>(context_snapshot->Reservations().size()), i);
184 : }
185 226 : payload_offset += payload_length;
186 : }
187 :
188 : DCHECK_EQ(total_length, payload_offset);
189 191 : v8::StartupData result = {data, static_cast<int>(total_length)};
190 :
191 : Checksum checksum(ChecksummedContent(&result));
192 : SetHeaderValue(data, kChecksumPartAOffset, checksum.a());
193 : SetHeaderValue(data, kChecksumPartBOffset, checksum.b());
194 :
195 191 : return result;
196 : }
197 :
198 301336 : uint32_t Snapshot::ExtractNumContexts(const v8::StartupData* data) {
199 301336 : CHECK_LT(kNumberOfContextsOffset, data->raw_size);
200 : uint32_t num_contexts = GetHeaderValue(data, kNumberOfContextsOffset);
201 150668 : return num_contexts;
202 : }
203 :
204 182844 : bool Snapshot::VerifyChecksum(const v8::StartupData* data) {
205 : base::ElapsedTimer timer;
206 60948 : if (FLAG_profile_deserialization) timer.Start();
207 : uint32_t expected_a = GetHeaderValue(data, kChecksumPartAOffset);
208 : uint32_t expected_b = GetHeaderValue(data, kChecksumPartBOffset);
209 : Checksum checksum(ChecksummedContent(data));
210 60948 : if (FLAG_profile_deserialization) {
211 5 : double ms = timer.Elapsed().InMillisecondsF();
212 5 : PrintF("[Verifying snapshot checksum took %0.3f ms]\n", ms);
213 : }
214 60948 : return checksum.Check(expected_a, expected_b);
215 : }
216 :
217 179432 : uint32_t Snapshot::ExtractContextOffset(const v8::StartupData* data,
218 : uint32_t index) {
219 : // Extract the offset of the context at a given index from the StartupData,
220 : // and check that it is within bounds.
221 : uint32_t context_offset =
222 89716 : GetHeaderValue(data, ContextSnapshotOffsetOffset(index));
223 89716 : CHECK_LT(context_offset, static_cast<uint32_t>(data->raw_size));
224 89716 : return context_offset;
225 : }
226 :
227 301246 : bool Snapshot::ExtractRehashability(const v8::StartupData* data) {
228 150623 : CHECK_LT(kRehashabilityOffset, static_cast<uint32_t>(data->raw_size));
229 150623 : return GetHeaderValue(data, kRehashabilityOffset) != 0;
230 : }
231 :
232 : namespace {
233 121874 : Vector<const byte> ExtractData(const v8::StartupData* snapshot,
234 : uint32_t start_offset, uint32_t end_offset) {
235 121874 : CHECK_LT(start_offset, end_offset);
236 243748 : CHECK_LT(end_offset, snapshot->raw_size);
237 121874 : uint32_t length = end_offset - start_offset;
238 : const byte* data =
239 121874 : reinterpret_cast<const byte*>(snapshot->data + start_offset);
240 121874 : return Vector<const byte>(data, length);
241 : }
242 : } // namespace
243 :
244 121876 : Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
245 : DCHECK(SnapshotIsValid(data));
246 :
247 60938 : uint32_t num_contexts = ExtractNumContexts(data);
248 : return ExtractData(data, StartupSnapshotOffset(num_contexts),
249 121876 : GetHeaderValue(data, kReadOnlyOffsetOffset));
250 : }
251 :
252 60938 : Vector<const byte> Snapshot::ExtractReadOnlyData(const v8::StartupData* data) {
253 : DCHECK(SnapshotIsValid(data));
254 :
255 : return ExtractData(data, GetHeaderValue(data, kReadOnlyOffsetOffset),
256 60938 : GetHeaderValue(data, ContextSnapshotOffsetOffset(0)));
257 : }
258 :
259 89686 : Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
260 : uint32_t index) {
261 89686 : uint32_t num_contexts = ExtractNumContexts(data);
262 89686 : CHECK_LT(index, num_contexts);
263 :
264 89686 : uint32_t context_offset = ExtractContextOffset(data, index);
265 : uint32_t next_context_offset;
266 89686 : if (index == num_contexts - 1) {
267 89656 : next_context_offset = data->raw_size;
268 : } else {
269 30 : next_context_offset = ExtractContextOffset(data, index + 1);
270 60 : CHECK_LT(next_context_offset, data->raw_size);
271 : }
272 :
273 : const byte* context_data =
274 89686 : reinterpret_cast<const byte*>(data->data + context_offset);
275 89686 : uint32_t context_length = next_context_offset - context_offset;
276 89686 : return Vector<const byte>(context_data, context_length);
277 : }
278 :
279 60938 : void Snapshot::CheckVersion(const v8::StartupData* data) {
280 : char version[kVersionStringLength];
281 : memset(version, 0, kVersionStringLength);
282 60938 : CHECK_LT(kVersionStringOffset + kVersionStringLength,
283 : static_cast<uint32_t>(data->raw_size));
284 60938 : Version::GetString(Vector<char>(version, kVersionStringLength));
285 60938 : if (strncmp(version, data->data + kVersionStringOffset,
286 60938 : kVersionStringLength) != 0) {
287 0 : FATAL(
288 : "Version mismatch between V8 binary and snapshot.\n"
289 : "# V8 binary version: %.*s\n"
290 : "# Snapshot version: %.*s\n"
291 : "# The snapshot consists of %d bytes and contains %d context(s).",
292 : kVersionStringLength, version, kVersionStringLength,
293 : data->data + kVersionStringOffset, data->raw_size,
294 0 : ExtractNumContexts(data));
295 : }
296 60938 : }
297 :
298 2992 : SnapshotData::SnapshotData(const Serializer* serializer) {
299 : DisallowHeapAllocation no_gc;
300 : std::vector<Reservation> reservations = serializer->EncodeReservations();
301 2244 : const std::vector<byte>* payload = serializer->Payload();
302 :
303 : // Calculate sizes.
304 : uint32_t reservation_size =
305 1496 : static_cast<uint32_t>(reservations.size()) * kUInt32Size;
306 : uint32_t payload_offset = kHeaderSize + reservation_size;
307 748 : uint32_t padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset);
308 : uint32_t size =
309 748 : padded_payload_offset + static_cast<uint32_t>(payload->size());
310 : DCHECK(IsAligned(size, kPointerAlignment));
311 :
312 : // Allocate backing store and create result data.
313 748 : AllocateData(size);
314 :
315 : // Zero out pre-payload data. Part of that is only used for padding.
316 748 : memset(data_, 0, padded_payload_offset);
317 :
318 : // Set header values.
319 : SetMagicNumber();
320 1496 : SetHeaderValue(kNumReservationsOffset, static_cast<int>(reservations.size()));
321 748 : SetHeaderValue(kPayloadLengthOffset, static_cast<int>(payload->size()));
322 :
323 : // Copy reservation chunk sizes.
324 : CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.data()),
325 1496 : reservation_size);
326 :
327 : // Copy serialized data.
328 : CopyBytes(data_ + padded_payload_offset, payload->data(),
329 748 : static_cast<size_t>(payload->size()));
330 748 : }
331 :
332 211710 : std::vector<SerializedData::Reservation> SnapshotData::Reservations() const {
333 211710 : uint32_t size = GetHeaderValue(kNumReservationsOffset);
334 211710 : std::vector<SerializedData::Reservation> reservations(size);
335 : memcpy(reservations.data(), data_ + kHeaderSize,
336 211712 : size * sizeof(SerializedData::Reservation));
337 211712 : return reservations;
338 : }
339 :
340 211686 : Vector<const byte> SnapshotData::Payload() const {
341 : uint32_t reservations_size =
342 423372 : GetHeaderValue(kNumReservationsOffset) * kUInt32Size;
343 : uint32_t padded_payload_offset =
344 211686 : POINTER_SIZE_ALIGN(kHeaderSize + reservations_size);
345 211686 : const byte* payload = data_ + padded_payload_offset;
346 : uint32_t length = GetHeaderValue(kPayloadLengthOffset);
347 : DCHECK_EQ(data_ + size_, payload + length);
348 211686 : return Vector<const byte>(payload, length);
349 : }
350 :
351 : } // namespace internal
352 178779 : } // namespace v8
|