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/api.h"
10 : #include "src/base/platform/platform.h"
11 : #include "src/objects-inl.h"
12 : #include "src/snapshot/builtin-deserializer.h"
13 : #include "src/snapshot/builtin-serializer.h"
14 : #include "src/snapshot/partial-deserializer.h"
15 : #include "src/snapshot/snapshot-source-sink.h"
16 : #include "src/snapshot/startup-deserializer.h"
17 : #include "src/utils.h"
18 : #include "src/version.h"
19 :
20 : namespace v8 {
21 : namespace internal {
22 :
23 : #ifdef DEBUG
24 : bool Snapshot::SnapshotIsValid(const v8::StartupData* snapshot_blob) {
25 : return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
26 : }
27 : #endif // DEBUG
28 :
29 38 : bool Snapshot::HasContextSnapshot(Isolate* isolate, size_t index) {
30 : // Do not use snapshots if the isolate is used to create snapshots.
31 : const v8::StartupData* blob = isolate->snapshot_blob();
32 38 : if (blob == nullptr) return false;
33 38 : if (blob->data == nullptr) return false;
34 38 : size_t num_contexts = static_cast<size_t>(ExtractNumContexts(blob));
35 38 : return index < num_contexts;
36 : }
37 :
38 109875 : bool Snapshot::Initialize(Isolate* isolate) {
39 54937 : if (!isolate->snapshot_available()) return false;
40 : base::ElapsedTimer timer;
41 54938 : if (FLAG_profile_deserialization) timer.Start();
42 :
43 : const v8::StartupData* blob = isolate->snapshot_blob();
44 54938 : CheckVersion(blob);
45 54938 : Vector<const byte> startup_data = ExtractStartupData(blob);
46 : SnapshotData startup_snapshot_data(startup_data);
47 54938 : Vector<const byte> builtin_data = ExtractBuiltinData(blob);
48 : BuiltinSnapshotData builtin_snapshot_data(builtin_data);
49 : StartupDeserializer deserializer(&startup_snapshot_data,
50 : &builtin_snapshot_data);
51 54938 : deserializer.SetRehashability(ExtractRehashability(blob));
52 54938 : bool success = isolate->Init(&deserializer);
53 54938 : if (FLAG_profile_deserialization) {
54 5 : double ms = timer.Elapsed().InMillisecondsF();
55 : int bytes = startup_data.length();
56 5 : PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
57 : }
58 : return success;
59 : }
60 :
61 83556 : MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
62 167092 : Isolate* isolate, Handle<JSGlobalProxy> global_proxy, size_t context_index,
63 : v8::DeserializeEmbedderFieldsCallback embedder_fields_deserializer) {
64 83556 : if (!isolate->snapshot_available()) return Handle<Context>();
65 : base::ElapsedTimer timer;
66 83536 : if (FLAG_profile_deserialization) timer.Start();
67 :
68 : const v8::StartupData* blob = isolate->snapshot_blob();
69 83536 : bool can_rehash = ExtractRehashability(blob);
70 : Vector<const byte> context_data =
71 83536 : 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 83536 : embedder_fields_deserializer);
77 :
78 : Handle<Context> result;
79 83536 : if (!maybe_result.ToHandle(&result)) return MaybeHandle<Context>();
80 :
81 83536 : 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 83536 : return result;
88 : }
89 :
90 : // static
91 201524 : Code* Snapshot::DeserializeBuiltin(Isolate* isolate, int builtin_id) {
92 : base::ElapsedTimer timer;
93 100762 : if (FLAG_profile_deserialization) timer.Start();
94 :
95 : const v8::StartupData* blob = isolate->snapshot_blob();
96 100762 : Vector<const byte> builtin_data = Snapshot::ExtractBuiltinData(blob);
97 : BuiltinSnapshotData builtin_snapshot_data(builtin_data);
98 :
99 100762 : CodeSpaceMemoryModificationScope code_allocation(isolate->heap());
100 100762 : BuiltinDeserializer builtin_deserializer(isolate, &builtin_snapshot_data);
101 100762 : Code* code = builtin_deserializer.DeserializeBuiltin(builtin_id);
102 : DCHECK_EQ(code, isolate->builtins()->builtin(builtin_id));
103 :
104 100762 : if (FLAG_profile_deserialization) {
105 0 : double ms = timer.Elapsed().InMillisecondsF();
106 0 : int bytes = code->Size();
107 : PrintF("[Deserializing builtin %s (%d bytes) took %0.3f ms]\n",
108 0 : Builtins::name(builtin_id), bytes, ms);
109 : }
110 :
111 100762 : return code;
112 : }
113 :
114 121 : void ProfileDeserialization(
115 : const SnapshotData* startup_snapshot, const SnapshotData* builtin_snapshot,
116 10 : const std::vector<SnapshotData*>& context_snapshots) {
117 121 : if (FLAG_profile_deserialization) {
118 : int startup_total = 0;
119 5 : PrintF("Deserialization will reserve:\n");
120 30 : for (const auto& reservation : startup_snapshot->Reservations()) {
121 25 : startup_total += reservation.chunk_size();
122 : }
123 5 : for (const auto& reservation : builtin_snapshot->Reservations()) {
124 0 : startup_total += reservation.chunk_size();
125 : }
126 5 : PrintF("%10d bytes per isolate\n", startup_total);
127 20 : for (size_t i = 0; i < context_snapshots.size(); i++) {
128 : int context_total = 0;
129 35 : for (const auto& reservation : context_snapshots[i]->Reservations()) {
130 25 : context_total += reservation.chunk_size();
131 : }
132 5 : PrintF("%10d bytes per context #%zu\n", context_total, i);
133 : }
134 : }
135 121 : }
136 :
137 121 : v8::StartupData Snapshot::CreateSnapshotBlob(
138 242 : const SnapshotData* startup_snapshot,
139 : const BuiltinSnapshotData* builtin_snapshot,
140 262 : const std::vector<SnapshotData*>& context_snapshots, bool can_be_rehashed) {
141 121 : uint32_t num_contexts = static_cast<uint32_t>(context_snapshots.size());
142 121 : uint32_t startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
143 : uint32_t total_length = startup_snapshot_offset;
144 121 : total_length += static_cast<uint32_t>(startup_snapshot->RawData().length());
145 242 : total_length += static_cast<uint32_t>(builtin_snapshot->RawData().length());
146 383 : for (const auto context_snapshot : context_snapshots) {
147 141 : total_length += static_cast<uint32_t>(context_snapshot->RawData().length());
148 : }
149 :
150 121 : ProfileDeserialization(startup_snapshot, builtin_snapshot, context_snapshots);
151 :
152 121 : char* data = new char[total_length];
153 : SetHeaderValue(data, kNumberOfContextsOffset, num_contexts);
154 121 : SetHeaderValue(data, kRehashabilityOffset, can_be_rehashed ? 1 : 0);
155 :
156 : // Write version string into snapshot data.
157 121 : memset(data + kVersionStringOffset, 0, kVersionStringLength);
158 : Version::GetString(
159 121 : Vector<char>(data + kVersionStringOffset, kVersionStringLength));
160 :
161 : // Startup snapshot (isolate-specific data).
162 : uint32_t payload_offset = startup_snapshot_offset;
163 : uint32_t payload_length =
164 : static_cast<uint32_t>(startup_snapshot->RawData().length());
165 : CopyBytes(data + payload_offset,
166 : reinterpret_cast<const char*>(startup_snapshot->RawData().start()),
167 121 : payload_length);
168 121 : if (FLAG_profile_deserialization) {
169 : PrintF("Snapshot blob consists of:\n%10d bytes for startup\n",
170 5 : payload_length);
171 : }
172 121 : payload_offset += payload_length;
173 :
174 : // Builtins.
175 : SetHeaderValue(data, kBuiltinOffsetOffset, payload_offset);
176 : payload_length = builtin_snapshot->RawData().length();
177 : CopyBytes(data + payload_offset,
178 : reinterpret_cast<const char*>(builtin_snapshot->RawData().start()),
179 121 : payload_length);
180 121 : if (FLAG_profile_deserialization) {
181 5 : PrintF("%10d bytes for builtins\n", payload_length);
182 : }
183 121 : payload_offset += payload_length;
184 :
185 : // Partial snapshots (context-specific data).
186 262 : for (uint32_t i = 0; i < num_contexts; i++) {
187 141 : SetHeaderValue(data, ContextSnapshotOffsetOffset(i), payload_offset);
188 282 : SnapshotData* context_snapshot = context_snapshots[i];
189 : payload_length = context_snapshot->RawData().length();
190 : CopyBytes(
191 : data + payload_offset,
192 : reinterpret_cast<const char*>(context_snapshot->RawData().start()),
193 141 : payload_length);
194 141 : if (FLAG_profile_deserialization) {
195 5 : PrintF("%10d bytes for context #%d\n", payload_length, i);
196 : }
197 141 : payload_offset += payload_length;
198 : }
199 :
200 121 : v8::StartupData result = {data, static_cast<int>(total_length)};
201 : DCHECK_EQ(total_length, payload_offset);
202 121 : return result;
203 : }
204 :
205 277024 : uint32_t Snapshot::ExtractNumContexts(const v8::StartupData* data) {
206 277024 : CHECK_LT(kNumberOfContextsOffset, data->raw_size);
207 : uint32_t num_contexts = GetHeaderValue(data, kNumberOfContextsOffset);
208 138512 : return num_contexts;
209 : }
210 :
211 167102 : uint32_t Snapshot::ExtractContextOffset(const v8::StartupData* data,
212 : uint32_t index) {
213 : // Extract the offset of the context at a given index from the StartupData,
214 : // and check that it is within bounds.
215 : uint32_t context_offset =
216 83551 : GetHeaderValue(data, ContextSnapshotOffsetOffset(index));
217 83551 : CHECK_LT(context_offset, static_cast<uint32_t>(data->raw_size));
218 83551 : return context_offset;
219 : }
220 :
221 276948 : bool Snapshot::ExtractRehashability(const v8::StartupData* data) {
222 138474 : CHECK_LT(kRehashabilityOffset, static_cast<uint32_t>(data->raw_size));
223 138474 : return GetHeaderValue(data, kRehashabilityOffset) != 0;
224 : }
225 :
226 109876 : Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
227 54938 : uint32_t num_contexts = ExtractNumContexts(data);
228 54938 : uint32_t startup_offset = StartupSnapshotOffset(num_contexts);
229 109876 : CHECK_LT(startup_offset, data->raw_size);
230 : uint32_t builtin_offset = GetHeaderValue(data, kBuiltinOffsetOffset);
231 54938 : CHECK_LT(builtin_offset, data->raw_size);
232 54938 : CHECK_GT(builtin_offset, startup_offset);
233 54938 : uint32_t startup_length = builtin_offset - startup_offset;
234 : const byte* startup_data =
235 54938 : reinterpret_cast<const byte*>(data->data + startup_offset);
236 54938 : return Vector<const byte>(startup_data, startup_length);
237 : }
238 :
239 155700 : Vector<const byte> Snapshot::ExtractBuiltinData(const v8::StartupData* data) {
240 : DCHECK(SnapshotIsValid(data));
241 :
242 : uint32_t from_offset = GetHeaderValue(data, kBuiltinOffsetOffset);
243 311400 : CHECK_LT(from_offset, data->raw_size);
244 :
245 : uint32_t to_offset = GetHeaderValue(data, ContextSnapshotOffsetOffset(0));
246 155700 : CHECK_LT(to_offset, data->raw_size);
247 :
248 155700 : CHECK_GT(to_offset, from_offset);
249 155700 : uint32_t length = to_offset - from_offset;
250 : const byte* builtin_data =
251 155700 : reinterpret_cast<const byte*>(data->data + from_offset);
252 155700 : return Vector<const byte>(builtin_data, length);
253 : }
254 :
255 83536 : Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
256 : uint32_t index) {
257 83536 : uint32_t num_contexts = ExtractNumContexts(data);
258 83536 : CHECK_LT(index, num_contexts);
259 :
260 83536 : uint32_t context_offset = ExtractContextOffset(data, index);
261 : uint32_t next_context_offset;
262 83536 : if (index == num_contexts - 1) {
263 83521 : next_context_offset = data->raw_size;
264 : } else {
265 15 : next_context_offset = ExtractContextOffset(data, index + 1);
266 30 : CHECK_LT(next_context_offset, data->raw_size);
267 : }
268 :
269 : const byte* context_data =
270 83536 : reinterpret_cast<const byte*>(data->data + context_offset);
271 83536 : uint32_t context_length = next_context_offset - context_offset;
272 83536 : return Vector<const byte>(context_data, context_length);
273 : }
274 :
275 54937 : void Snapshot::CheckVersion(const v8::StartupData* data) {
276 : char version[kVersionStringLength];
277 : memset(version, 0, kVersionStringLength);
278 54937 : CHECK_LT(kVersionStringOffset + kVersionStringLength,
279 : static_cast<uint32_t>(data->raw_size));
280 54937 : Version::GetString(Vector<char>(version, kVersionStringLength));
281 109876 : if (memcmp(version, data->data + kVersionStringOffset,
282 109876 : kVersionStringLength) != 0) {
283 : V8_Fatal(__FILE__, __LINE__,
284 : "Version mismatch between V8 binary and snapshot.\n"
285 : "# V8 binary version: %.*s\n"
286 : "# Snapshot version: %.*s\n"
287 : "# The snapshot consists of %d bytes and contains %d context(s).",
288 : kVersionStringLength, version, kVersionStringLength,
289 : data->data + kVersionStringOffset, data->raw_size,
290 0 : ExtractNumContexts(data));
291 : }
292 54938 : }
293 :
294 : template <class AllocatorT>
295 2365 : SnapshotData::SnapshotData(const Serializer<AllocatorT>* serializer) {
296 : DisallowHeapAllocation no_gc;
297 : std::vector<Reservation> reservations = serializer->EncodeReservations();
298 1419 : const std::vector<byte>* payload = serializer->Payload();
299 :
300 : // Calculate sizes.
301 : uint32_t reservation_size =
302 946 : static_cast<uint32_t>(reservations.size()) * kUInt32Size;
303 : uint32_t size =
304 473 : kHeaderSize + reservation_size + static_cast<uint32_t>(payload->size());
305 :
306 : // Allocate backing store and create result data.
307 473 : AllocateData(size);
308 :
309 : // Set header values.
310 473 : SetMagicNumber(serializer->isolate());
311 946 : SetHeaderValue(kNumReservationsOffset, static_cast<int>(reservations.size()));
312 473 : SetHeaderValue(kPayloadLengthOffset, static_cast<int>(payload->size()));
313 :
314 : // Copy reservation chunk sizes.
315 473 : CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.data()),
316 946 : reservation_size);
317 :
318 : // Copy serialized data.
319 946 : CopyBytes(data_ + kHeaderSize + reservation_size, payload->data(),
320 946 : static_cast<size_t>(payload->size()));
321 473 : }
322 :
323 : // Explicit instantiation.
324 : template SnapshotData::SnapshotData(
325 : const Serializer<DefaultSerializerAllocator>* serializer);
326 :
327 239311 : Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
328 : return Vector<const Reservation>(
329 : reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
330 588528 : GetHeaderValue(kNumReservationsOffset));
331 : }
332 :
333 138519 : Vector<const byte> SnapshotData::Payload() const {
334 : uint32_t reservations_size =
335 277038 : GetHeaderValue(kNumReservationsOffset) * kUInt32Size;
336 138519 : const byte* payload = data_ + kHeaderSize + reservations_size;
337 : uint32_t length = GetHeaderValue(kPayloadLengthOffset);
338 : DCHECK_EQ(data_ + size_, payload + length);
339 138519 : return Vector<const byte>(payload, length);
340 : }
341 :
342 161 : BuiltinSnapshotData::BuiltinSnapshotData(const BuiltinSerializer* serializer)
343 161 : : SnapshotData(serializer) {}
344 :
345 155730 : Vector<const byte> BuiltinSnapshotData::Payload() const {
346 : uint32_t reservations_size =
347 311460 : GetHeaderValue(kNumReservationsOffset) * kUInt32Size;
348 155730 : const byte* payload = data_ + kHeaderSize + reservations_size;
349 : int builtin_offsets_size = Builtins::builtin_count * kUInt32Size;
350 : uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
351 : DCHECK_EQ(data_ + size_, payload + payload_length);
352 : DCHECK_GT(payload_length, builtin_offsets_size);
353 155730 : return Vector<const byte>(payload, payload_length - builtin_offsets_size);
354 : }
355 :
356 155730 : Vector<const uint32_t> BuiltinSnapshotData::BuiltinOffsets() const {
357 : uint32_t reservations_size =
358 311460 : GetHeaderValue(kNumReservationsOffset) * kUInt32Size;
359 155730 : const byte* payload = data_ + kHeaderSize + reservations_size;
360 : int builtin_offsets_size = Builtins::builtin_count * kUInt32Size;
361 : uint32_t payload_length = GetHeaderValue(kPayloadLengthOffset);
362 : DCHECK_EQ(data_ + size_, payload + payload_length);
363 : DCHECK_GT(payload_length, builtin_offsets_size);
364 : const uint32_t* data = reinterpret_cast<const uint32_t*>(
365 155730 : payload + payload_length - builtin_offsets_size);
366 155730 : return Vector<const uint32_t>(data, Builtins::builtin_count);
367 : }
368 :
369 : } // namespace internal
370 : } // namespace v8
|