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