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 125542 : bool Snapshot::Initialize(Isolate* isolate) {
34 62771 : if (!isolate->snapshot_available()) return false;
35 : RuntimeCallTimerScope rcs_timer(isolate,
36 62771 : RuntimeCallCounterId::kDeserializeIsolate);
37 : base::ElapsedTimer timer;
38 62771 : if (FLAG_profile_deserialization) timer.Start();
39 :
40 : const v8::StartupData* blob = isolate->snapshot_blob();
41 62771 : CheckVersion(blob);
42 62771 : CHECK(VerifyChecksum(blob));
43 62772 : Vector<const byte> startup_data = ExtractStartupData(blob);
44 : SnapshotData startup_snapshot_data(startup_data);
45 62771 : 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 62771 : deserializer.SetRehashability(ExtractRehashability(blob));
50 62772 : bool success = isolate->Init(&deserializer);
51 62770 : 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 91825 : MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
60 183605 : Isolate* isolate, Handle<JSGlobalProxy> global_proxy, size_t context_index,
61 : v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
62 91825 : if (!isolate->snapshot_available()) return Handle<Context>();
63 : RuntimeCallTimerScope rcs_timer(isolate,
64 91780 : RuntimeCallCounterId::kDeserializeContext);
65 : base::ElapsedTimer timer;
66 91780 : if (FLAG_profile_deserialization) timer.Start();
67 :
68 : const v8::StartupData* blob = isolate->snapshot_blob();
69 91780 : bool can_rehash = ExtractRehashability(blob);
70 : Vector<const byte> context_data =
71 91780 : 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 91780 : embedder_fields_deserializer);
77 :
78 : Handle<Context> result;
79 91780 : if (!maybe_result.ToHandle(&result)) return MaybeHandle<Context>();
80 :
81 91780 : 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 91780 : return result;
88 : }
89 :
90 186 : void ProfileDeserialization(
91 : const SnapshotData* read_only_snapshot,
92 : const SnapshotData* startup_snapshot,
93 10 : const std::vector<SnapshotData*>& context_snapshots) {
94 186 : 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 160 : for (const auto& reservation : context_snapshots[i]->Reservations()) {
107 145 : context_total += reservation.chunk_size();
108 : }
109 5 : PrintF("%10d bytes per context #%zu\n", context_total, i);
110 : }
111 : }
112 186 : }
113 :
114 186 : v8::StartupData Snapshot::CreateSnapshotBlob(
115 372 : const SnapshotData* startup_snapshot,
116 372 : const SnapshotData* read_only_snapshot,
117 407 : const std::vector<SnapshotData*>& context_snapshots, bool can_be_rehashed) {
118 186 : uint32_t num_contexts = static_cast<uint32_t>(context_snapshots.size());
119 186 : uint32_t startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
120 : uint32_t total_length = startup_snapshot_offset;
121 : DCHECK(IsAligned(total_length, kPointerAlignment));
122 186 : total_length += static_cast<uint32_t>(startup_snapshot->RawData().length());
123 : DCHECK(IsAligned(total_length, kPointerAlignment));
124 186 : total_length += static_cast<uint32_t>(read_only_snapshot->RawData().length());
125 : DCHECK(IsAligned(total_length, kPointerAlignment));
126 593 : for (const auto context_snapshot : context_snapshots) {
127 221 : 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 186 : context_snapshots);
133 :
134 186 : char* data = new char[total_length];
135 : // Zero out pre-payload data. Part of that is only used for padding.
136 186 : memset(data, 0, StartupSnapshotOffset(num_contexts));
137 :
138 : SetHeaderValue(data, kNumberOfContextsOffset, num_contexts);
139 186 : SetHeaderValue(data, kRehashabilityOffset, can_be_rehashed ? 1 : 0);
140 :
141 : // Write version string into snapshot data.
142 186 : memset(data + kVersionStringOffset, 0, kVersionStringLength);
143 : Version::GetString(
144 186 : 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 186 : payload_length);
153 186 : 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 186 : 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 186 : payload_length);
167 186 : if (FLAG_profile_deserialization) {
168 5 : PrintF("%10d bytes for read-only\n", payload_length);
169 : }
170 186 : payload_offset += payload_length;
171 :
172 : // Partial snapshots (context-specific data).
173 407 : for (uint32_t i = 0; i < num_contexts; i++) {
174 221 : SetHeaderValue(data, ContextSnapshotOffsetOffset(i), payload_offset);
175 442 : 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 221 : payload_length);
181 221 : 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 221 : payload_offset += payload_length;
186 : }
187 :
188 : DCHECK_EQ(total_length, payload_offset);
189 186 : 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 186 : return result;
196 : }
197 :
198 309192 : uint32_t Snapshot::ExtractNumContexts(const v8::StartupData* data) {
199 309192 : CHECK_LT(kNumberOfContextsOffset, data->raw_size);
200 : uint32_t num_contexts = GetHeaderValue(data, kNumberOfContextsOffset);
201 154596 : return num_contexts;
202 : }
203 :
204 188346 : bool Snapshot::VerifyChecksum(const v8::StartupData* data) {
205 : base::ElapsedTimer timer;
206 62782 : 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 62782 : 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 62782 : return checksum.Check(expected_a, expected_b);
215 : }
216 :
217 183620 : 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 91810 : GetHeaderValue(data, ContextSnapshotOffsetOffset(index));
223 91810 : CHECK_LT(context_offset, static_cast<uint32_t>(data->raw_size));
224 91810 : return context_offset;
225 : }
226 :
227 309104 : bool Snapshot::ExtractRehashability(const v8::StartupData* data) {
228 154552 : CHECK_LT(kRehashabilityOffset, static_cast<uint32_t>(data->raw_size));
229 154552 : return GetHeaderValue(data, kRehashabilityOffset) != 0;
230 : }
231 :
232 : namespace {
233 125541 : Vector<const byte> ExtractData(const v8::StartupData* snapshot,
234 : uint32_t start_offset, uint32_t end_offset) {
235 125541 : CHECK_LT(start_offset, end_offset);
236 251082 : CHECK_LT(end_offset, snapshot->raw_size);
237 125541 : uint32_t length = end_offset - start_offset;
238 : const byte* data =
239 125541 : reinterpret_cast<const byte*>(snapshot->data + start_offset);
240 125541 : return Vector<const byte>(data, length);
241 : }
242 : } // namespace
243 :
244 125541 : Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
245 : DCHECK(SnapshotIsValid(data));
246 :
247 62771 : uint32_t num_contexts = ExtractNumContexts(data);
248 : return ExtractData(data, StartupSnapshotOffset(num_contexts),
249 125540 : GetHeaderValue(data, kReadOnlyOffsetOffset));
250 : }
251 :
252 62771 : Vector<const byte> Snapshot::ExtractReadOnlyData(const v8::StartupData* data) {
253 : DCHECK(SnapshotIsValid(data));
254 :
255 : return ExtractData(data, GetHeaderValue(data, kReadOnlyOffsetOffset),
256 62771 : GetHeaderValue(data, ContextSnapshotOffsetOffset(0)));
257 : }
258 :
259 91780 : Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
260 : uint32_t index) {
261 91780 : uint32_t num_contexts = ExtractNumContexts(data);
262 91780 : CHECK_LT(index, num_contexts);
263 :
264 91780 : uint32_t context_offset = ExtractContextOffset(data, index);
265 : uint32_t next_context_offset;
266 91780 : if (index == num_contexts - 1) {
267 91750 : 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 91780 : reinterpret_cast<const byte*>(data->data + context_offset);
275 91780 : uint32_t context_length = next_context_offset - context_offset;
276 91780 : return Vector<const byte>(context_data, context_length);
277 : }
278 :
279 62771 : void Snapshot::CheckVersion(const v8::StartupData* data) {
280 : char version[kVersionStringLength];
281 : memset(version, 0, kVersionStringLength);
282 62771 : CHECK_LT(kVersionStringOffset + kVersionStringLength,
283 : static_cast<uint32_t>(data->raw_size));
284 62771 : Version::GetString(Vector<char>(version, kVersionStringLength));
285 62771 : if (strncmp(version, data->data + kVersionStringOffset,
286 62771 : 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 62771 : }
297 :
298 2932 : SnapshotData::SnapshotData(const Serializer* serializer) {
299 : DisallowHeapAllocation no_gc;
300 : std::vector<Reservation> reservations = serializer->EncodeReservations();
301 2199 : const std::vector<byte>* payload = serializer->Payload();
302 :
303 : // Calculate sizes.
304 : uint32_t reservation_size =
305 1466 : static_cast<uint32_t>(reservations.size()) * kUInt32Size;
306 : uint32_t payload_offset = kHeaderSize + reservation_size;
307 733 : uint32_t padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset);
308 : uint32_t size =
309 733 : padded_payload_offset + static_cast<uint32_t>(payload->size());
310 : DCHECK(IsAligned(size, kPointerAlignment));
311 :
312 : // Allocate backing store and create result data.
313 733 : AllocateData(size);
314 :
315 : // Zero out pre-payload data. Part of that is only used for padding.
316 733 : memset(data_, 0, padded_payload_offset);
317 :
318 : // Set header values.
319 : SetMagicNumber();
320 1466 : SetHeaderValue(kNumReservationsOffset, static_cast<int>(reservations.size()));
321 733 : SetHeaderValue(kPayloadLengthOffset, static_cast<int>(payload->size()));
322 :
323 : // Copy reservation chunk sizes.
324 : CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.data()),
325 1466 : reservation_size);
326 :
327 : // Copy serialized data.
328 : CopyBytes(data_ + padded_payload_offset, payload->data(),
329 733 : static_cast<size_t>(payload->size()));
330 733 : }
331 :
332 217473 : std::vector<SerializedData::Reservation> SnapshotData::Reservations() const {
333 217473 : uint32_t size = GetHeaderValue(kNumReservationsOffset);
334 217473 : std::vector<SerializedData::Reservation> reservations(size);
335 : memcpy(reservations.data(), data_ + kHeaderSize,
336 217473 : size * sizeof(SerializedData::Reservation));
337 217473 : return reservations;
338 : }
339 :
340 217447 : Vector<const byte> SnapshotData::Payload() const {
341 : uint32_t reservations_size =
342 434894 : GetHeaderValue(kNumReservationsOffset) * kUInt32Size;
343 : uint32_t padded_payload_offset =
344 217447 : POINTER_SIZE_ALIGN(kHeaderSize + reservations_size);
345 217447 : const byte* payload = data_ + padded_payload_offset;
346 : uint32_t length = GetHeaderValue(kPayloadLengthOffset);
347 : DCHECK_EQ(data_ + size_, payload + length);
348 217447 : return Vector<const byte>(payload, length);
349 : }
350 :
351 : } // namespace internal
352 183867 : } // namespace v8
|