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/full-codegen/full-codegen.h"
12#include "src/objects-inl.h"
13#include "src/snapshot/deserializer.h"
14#include "src/snapshot/snapshot-source-sink.h"
15#include "src/version.h"
16
17namespace v8 {
18namespace internal {
19
20#ifdef DEBUG
21bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
22  return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
23}
24#endif  // DEBUG
25
26bool Snapshot::HasContextSnapshot(Isolate* isolate, size_t index) {
27  // Do not use snapshots if the isolate is used to create snapshots.
28  const v8::StartupData* blob = isolate->snapshot_blob();
29  if (blob == nullptr) return false;
30  if (blob->data == nullptr) return false;
31  size_t num_contexts = static_cast<size_t>(ExtractNumContexts(blob));
32  return index < num_contexts;
33}
34
35bool Snapshot::Initialize(Isolate* isolate) {
36  if (!isolate->snapshot_available()) return false;
37  base::ElapsedTimer timer;
38  if (FLAG_profile_deserialization) timer.Start();
39
40  const v8::StartupData* blob = isolate->snapshot_blob();
41  Vector<const byte> startup_data = ExtractStartupData(blob);
42  SnapshotData snapshot_data(startup_data);
43  Deserializer deserializer(&snapshot_data);
44  bool success = isolate->Init(&deserializer);
45  if (FLAG_profile_deserialization) {
46    double ms = timer.Elapsed().InMillisecondsF();
47    int bytes = startup_data.length();
48    PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
49  }
50  return success;
51}
52
53MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
54    Isolate* isolate, Handle<JSGlobalProxy> global_proxy, size_t context_index,
55    v8::DeserializeInternalFieldsCallback internal_fields_deserializer) {
56  if (!isolate->snapshot_available()) return Handle<Context>();
57  base::ElapsedTimer timer;
58  if (FLAG_profile_deserialization) timer.Start();
59
60  const v8::StartupData* blob = isolate->snapshot_blob();
61  Vector<const byte> context_data =
62      ExtractContextData(blob, static_cast<int>(context_index));
63  SnapshotData snapshot_data(context_data);
64  Deserializer deserializer(&snapshot_data);
65
66  MaybeHandle<Object> maybe_context = deserializer.DeserializePartial(
67      isolate, global_proxy, internal_fields_deserializer);
68  Handle<Object> result;
69  if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
70  CHECK(result->IsContext());
71  if (FLAG_profile_deserialization) {
72    double ms = timer.Elapsed().InMillisecondsF();
73    int bytes = context_data.length();
74    PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n",
75           context_index, bytes, ms);
76  }
77  return Handle<Context>::cast(result);
78}
79
80void ProfileDeserialization(const SnapshotData* startup_snapshot,
81                            const List<SnapshotData*>* context_snapshots) {
82  if (FLAG_profile_deserialization) {
83    int startup_total = 0;
84    PrintF("Deserialization will reserve:\n");
85    for (const auto& reservation : startup_snapshot->Reservations()) {
86      startup_total += reservation.chunk_size();
87    }
88    PrintF("%10d bytes per isolate\n", startup_total);
89    for (int i = 0; i < context_snapshots->length(); i++) {
90      int context_total = 0;
91      for (const auto& reservation : context_snapshots->at(i)->Reservations()) {
92        context_total += reservation.chunk_size();
93      }
94      PrintF("%10d bytes per context #%d\n", context_total, i);
95    }
96  }
97}
98
99v8::StartupData Snapshot::CreateSnapshotBlob(
100    const SnapshotData* startup_snapshot,
101    const List<SnapshotData*>* context_snapshots) {
102  int num_contexts = context_snapshots->length();
103  int startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
104  int total_length = startup_snapshot_offset;
105  total_length += startup_snapshot->RawData().length();
106  for (const auto& context_snapshot : *context_snapshots) {
107    total_length += context_snapshot->RawData().length();
108  }
109
110  ProfileDeserialization(startup_snapshot, context_snapshots);
111
112  char* data = new char[total_length];
113  memcpy(data + kNumberOfContextsOffset, &num_contexts, kInt32Size);
114  int payload_offset = StartupSnapshotOffset(num_contexts);
115  int payload_length = startup_snapshot->RawData().length();
116  memcpy(data + payload_offset, startup_snapshot->RawData().start(),
117         payload_length);
118  if (FLAG_profile_deserialization) {
119    PrintF("Snapshot blob consists of:\n%10d bytes for startup\n",
120           payload_length);
121  }
122  payload_offset += payload_length;
123  for (int i = 0; i < num_contexts; i++) {
124    memcpy(data + ContextSnapshotOffsetOffset(i), &payload_offset, kInt32Size);
125    SnapshotData* context_snapshot = context_snapshots->at(i);
126    payload_length = context_snapshot->RawData().length();
127    memcpy(data + payload_offset, context_snapshot->RawData().start(),
128           payload_length);
129    if (FLAG_profile_deserialization) {
130      PrintF("%10d bytes for context #%d\n", payload_length, i);
131    }
132    payload_offset += payload_length;
133  }
134
135  v8::StartupData result = {data, total_length};
136  return result;
137}
138
139int Snapshot::ExtractNumContexts(const v8::StartupData* data) {
140  CHECK_LT(kNumberOfContextsOffset, data->raw_size);
141  int num_contexts;
142  memcpy(&num_contexts, data->data + kNumberOfContextsOffset, kInt32Size);
143  return num_contexts;
144}
145
146Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
147  int num_contexts = ExtractNumContexts(data);
148  int startup_offset = StartupSnapshotOffset(num_contexts);
149  CHECK_LT(startup_offset, data->raw_size);
150  int first_context_offset;
151  memcpy(&first_context_offset, data->data + ContextSnapshotOffsetOffset(0),
152         kInt32Size);
153  CHECK_LT(first_context_offset, data->raw_size);
154  int startup_length = first_context_offset - startup_offset;
155  const byte* startup_data =
156      reinterpret_cast<const byte*>(data->data + startup_offset);
157  return Vector<const byte>(startup_data, startup_length);
158}
159
160Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
161                                                int index) {
162  int num_contexts = ExtractNumContexts(data);
163  CHECK_LT(index, num_contexts);
164
165  int context_offset;
166  memcpy(&context_offset, data->data + ContextSnapshotOffsetOffset(index),
167         kInt32Size);
168  int next_context_offset;
169  if (index == num_contexts - 1) {
170    next_context_offset = data->raw_size;
171  } else {
172    memcpy(&next_context_offset,
173           data->data + ContextSnapshotOffsetOffset(index + 1), kInt32Size);
174    CHECK_LT(next_context_offset, data->raw_size);
175  }
176
177  const byte* context_data =
178      reinterpret_cast<const byte*>(data->data + context_offset);
179  int context_length = next_context_offset - context_offset;
180  return Vector<const byte>(context_data, context_length);
181}
182
183SnapshotData::SnapshotData(const Serializer* serializer) {
184  DisallowHeapAllocation no_gc;
185  List<Reservation> reservations;
186  serializer->EncodeReservations(&reservations);
187  const List<byte>* payload = serializer->sink()->data();
188
189  // Calculate sizes.
190  int reservation_size = reservations.length() * kInt32Size;
191  int size = kHeaderSize + reservation_size + payload->length();
192
193  // Allocate backing store and create result data.
194  AllocateData(size);
195
196  // Set header values.
197  SetMagicNumber(serializer->isolate());
198  SetHeaderValue(kCheckSumOffset, Version::Hash());
199  SetHeaderValue(kNumReservationsOffset, reservations.length());
200  SetHeaderValue(kPayloadLengthOffset, payload->length());
201
202  // Copy reservation chunk sizes.
203  CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
204            reservation_size);
205
206  // Copy serialized data.
207  CopyBytes(data_ + kHeaderSize + reservation_size, payload->begin(),
208            static_cast<size_t>(payload->length()));
209}
210
211bool SnapshotData::IsSane() {
212  return GetHeaderValue(kCheckSumOffset) == Version::Hash();
213}
214
215Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
216  return Vector<const Reservation>(
217      reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
218      GetHeaderValue(kNumReservationsOffset));
219}
220
221Vector<const byte> SnapshotData::Payload() const {
222  int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size;
223  const byte* payload = data_ + kHeaderSize + reservations_size;
224  int length = GetHeaderValue(kPayloadLengthOffset);
225  DCHECK_EQ(data_ + size_, payload + length);
226  return Vector<const byte>(payload, length);
227}
228
229}  // namespace internal
230}  // namespace v8
231