V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
snapshot-common.cc
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/snapshot/partial-deserializer.h"
11 #include "src/snapshot/startup-deserializer.h"
12 #include "src/version.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 #ifdef DEBUG
18 bool Snapshot::SnapshotIsValid(const v8::StartupData* snapshot_blob) {
19  return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
20 }
21 #endif // DEBUG
22 
23 bool Snapshot::HasContextSnapshot(Isolate* isolate, size_t index) {
24  // Do not use snapshots if the isolate is used to create snapshots.
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;
30 }
31 
32 bool Snapshot::Initialize(Isolate* isolate) {
33  if (!isolate->snapshot_available()) return false;
34  base::ElapsedTimer timer;
35  if (FLAG_profile_deserialization) timer.Start();
36 
37  const v8::StartupData* blob = isolate->snapshot_blob();
38  CheckVersion(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);
52  }
53  return success;
54 }
55 
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();
62 
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);
68 
69  MaybeHandle<Context> maybe_result = PartialDeserializer::DeserializeContext(
70  isolate, &snapshot_data, can_rehash, global_proxy,
71  embedder_fields_deserializer);
72 
73  Handle<Context> result;
74  if (!maybe_result.ToHandle(&result)) return MaybeHandle<Context>();
75 
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);
81  }
82  return result;
83 }
84 
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();
94  }
95  for (const auto& reservation : startup_snapshot->Reservations()) {
96  startup_total += reservation.chunk_size();
97  }
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();
103  }
104  PrintF("%10d bytes per context #%zu\n", context_total, i);
105  }
106  }
107 }
108 
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) {
113  uint32_t num_contexts = static_cast<uint32_t>(context_snapshots.size());
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));
124  }
125 
126  ProfileDeserialization(read_only_snapshot, startup_snapshot,
127  context_snapshots);
128 
129  char* data = new char[total_length];
130  // Zero out pre-payload data. Part of that is only used for padding.
131  memset(data, 0, StartupSnapshotOffset(num_contexts));
132 
133  SetHeaderValue(data, kNumberOfContextsOffset, num_contexts);
134  SetHeaderValue(data, kRehashabilityOffset, can_be_rehashed ? 1 : 0);
135 
136  // Write version string into snapshot data.
137  memset(data + kVersionStringOffset, 0, kVersionStringLength);
138  Version::GetString(
139  Vector<char>(data + kVersionStringOffset, kVersionStringLength));
140 
141  // Startup snapshot (isolate-specific data).
142  uint32_t payload_offset = startup_snapshot_offset;
143  uint32_t payload_length =
144  static_cast<uint32_t>(startup_snapshot->RawData().length());
145  CopyBytes(data + payload_offset,
146  reinterpret_cast<const char*>(startup_snapshot->RawData().start()),
147  payload_length);
148  if (FLAG_profile_deserialization) {
149  PrintF("Snapshot blob consists of:\n%10d bytes in %d chunks for startup\n",
150  payload_length,
151  static_cast<uint32_t>(startup_snapshot->Reservations().size()));
152  }
153  payload_offset += payload_length;
154 
155  // Read-only.
156  SetHeaderValue(data, kReadOnlyOffsetOffset, payload_offset);
157  payload_length = read_only_snapshot->RawData().length();
158  CopyBytes(
159  data + payload_offset,
160  reinterpret_cast<const char*>(read_only_snapshot->RawData().start()),
161  payload_length);
162  if (FLAG_profile_deserialization) {
163  PrintF("%10d bytes for read-only\n", payload_length);
164  }
165  payload_offset += payload_length;
166 
167  // Partial snapshots (context-specific data).
168  for (uint32_t i = 0; i < num_contexts; i++) {
169  SetHeaderValue(data, ContextSnapshotOffsetOffset(i), payload_offset);
170  SnapshotData* context_snapshot = context_snapshots[i];
171  payload_length = context_snapshot->RawData().length();
172  CopyBytes(
173  data + payload_offset,
174  reinterpret_cast<const char*>(context_snapshot->RawData().start()),
175  payload_length);
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);
179  }
180  payload_offset += payload_length;
181  }
182 
183  DCHECK_EQ(total_length, payload_offset);
184  v8::StartupData result = {data, static_cast<int>(total_length)};
185 
186  Checksum checksum(ChecksummedContent(&result));
187  SetHeaderValue(data, kChecksumPartAOffset, checksum.a());
188  SetHeaderValue(data, kChecksumPartBOffset, checksum.b());
189 
190  return result;
191 }
192 
193 uint32_t Snapshot::ExtractNumContexts(const v8::StartupData* data) {
194  CHECK_LT(kNumberOfContextsOffset, data->raw_size);
195  uint32_t num_contexts = GetHeaderValue(data, kNumberOfContextsOffset);
196  return num_contexts;
197 }
198 
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);
208  }
209  return checksum.Check(expected_a, expected_b);
210 }
211 
212 uint32_t Snapshot::ExtractContextOffset(const v8::StartupData* data,
213  uint32_t index) {
214  // Extract the offset of the context at a given index from the StartupData,
215  // and check that it is within bounds.
216  uint32_t context_offset =
217  GetHeaderValue(data, ContextSnapshotOffsetOffset(index));
218  CHECK_LT(context_offset, static_cast<uint32_t>(data->raw_size));
219  return context_offset;
220 }
221 
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;
225 }
226 
227 namespace {
228 Vector<const byte> ExtractData(const v8::StartupData* snapshot,
229  uint32_t start_offset, uint32_t end_offset) {
230  CHECK_LT(start_offset, end_offset);
231  CHECK_LT(end_offset, snapshot->raw_size);
232  uint32_t length = end_offset - start_offset;
233  const byte* data =
234  reinterpret_cast<const byte*>(snapshot->data + start_offset);
235  return Vector<const byte>(data, length);
236 }
237 } // namespace
238 
239 Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
240  DCHECK(SnapshotIsValid(data));
241 
242  uint32_t num_contexts = ExtractNumContexts(data);
243  return ExtractData(data, StartupSnapshotOffset(num_contexts),
244  GetHeaderValue(data, kReadOnlyOffsetOffset));
245 }
246 
247 Vector<const byte> Snapshot::ExtractReadOnlyData(const v8::StartupData* data) {
248  DCHECK(SnapshotIsValid(data));
249 
250  return ExtractData(data, GetHeaderValue(data, kReadOnlyOffsetOffset),
251  GetHeaderValue(data, ContextSnapshotOffsetOffset(0)));
252 }
253 
254 Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
255  uint32_t index) {
256  uint32_t num_contexts = ExtractNumContexts(data);
257  CHECK_LT(index, num_contexts);
258 
259  uint32_t context_offset = ExtractContextOffset(data, index);
260  uint32_t next_context_offset;
261  if (index == num_contexts - 1) {
262  next_context_offset = data->raw_size;
263  } else {
264  next_context_offset = ExtractContextOffset(data, index + 1);
265  CHECK_LT(next_context_offset, data->raw_size);
266  }
267 
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);
272 }
273 
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) {
282  FATAL(
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));
290  }
291 }
292 
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();
297 
298  // Calculate sizes.
299  uint32_t reservation_size =
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);
303  uint32_t size =
304  padded_payload_offset + static_cast<uint32_t>(payload->size());
305  DCHECK(IsAligned(size, kPointerAlignment));
306 
307  // Allocate backing store and create result data.
308  AllocateData(size);
309 
310  // Zero out pre-payload data. Part of that is only used for padding.
311  memset(data_, 0, padded_payload_offset);
312 
313  // Set header values.
314  SetMagicNumber(serializer->isolate());
315  SetHeaderValue(kNumReservationsOffset, static_cast<int>(reservations.size()));
316  SetHeaderValue(kPayloadLengthOffset, static_cast<int>(payload->size()));
317 
318  // Copy reservation chunk sizes.
319  CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.data()),
320  reservation_size);
321 
322  // Copy serialized data.
323  CopyBytes(data_ + padded_payload_offset, payload->data(),
324  static_cast<size_t>(payload->size()));
325 }
326 
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));
332  return reservations;
333 }
334 
335 Vector<const byte> SnapshotData::Payload() const {
336  uint32_t reservations_size =
337  GetHeaderValue(kNumReservationsOffset) * kUInt32Size;
338  uint32_t padded_payload_offset =
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);
344 }
345 
346 } // namespace internal
347 } // namespace v8
Definition: libplatform.h:13