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
17 namespace v8 {
18 namespace internal {
19
20 #ifdef DEBUG
SnapshotIsValid(v8::StartupData * snapshot_blob)21 bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
22 return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
23 }
24 #endif // DEBUG
25
HasContextSnapshot(Isolate * isolate,size_t index)26 bool 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
Initialize(Isolate * isolate)35 bool 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
NewContextFromSnapshot(Isolate * isolate,Handle<JSGlobalProxy> global_proxy,size_t context_index,v8::DeserializeInternalFieldsCallback internal_fields_deserializer)53 MaybeHandle<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
ProfileDeserialization(const SnapshotData * startup_snapshot,const List<SnapshotData * > * context_snapshots)80 void 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
CreateSnapshotBlob(const SnapshotData * startup_snapshot,const List<SnapshotData * > * context_snapshots)99 v8::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
ExtractNumContexts(const v8::StartupData * data)139 int 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
ExtractStartupData(const v8::StartupData * data)146 Vector<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
ExtractContextData(const v8::StartupData * data,int index)160 Vector<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
SnapshotData(const Serializer * serializer)183 SnapshotData::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
IsSane()211 bool SnapshotData::IsSane() {
212 return GetHeaderValue(kCheckSumOffset) == Version::Hash();
213 }
214
Reservations() const215 Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
216 return Vector<const Reservation>(
217 reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
218 GetHeaderValue(kNumReservationsOffset));
219 }
220
Payload() const221 Vector<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