blob: 5eac4af6eeb08f42e75cdf2359bfa315f88d192b [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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"
Ben Murdochda12d292016-06-02 14:46:10 +010012#include "src/snapshot/deserializer.h"
13#include "src/snapshot/snapshot-source-sink.h"
14#include "src/version.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000015
16namespace v8 {
17namespace internal {
18
19#ifdef DEBUG
20bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
Ben Murdoch61f157c2016-09-16 13:49:30 +010021 return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022}
23#endif // DEBUG
24
25
26bool Snapshot::HaveASnapshotToStartFrom(Isolate* isolate) {
27 // Do not use snapshots if the isolate is used to create snapshots.
28 return isolate->snapshot_blob() != NULL &&
29 isolate->snapshot_blob()->data != NULL;
30}
31
32
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033uint32_t Snapshot::SizeOfFirstPage(Isolate* isolate, AllocationSpace space) {
34 DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE);
35 if (!isolate->snapshot_available()) {
36 return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space));
37 }
38 uint32_t size;
39 int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size;
40 memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size);
41 return size;
42}
43
44
45bool Snapshot::Initialize(Isolate* isolate) {
46 if (!isolate->snapshot_available()) return false;
47 base::ElapsedTimer timer;
48 if (FLAG_profile_deserialization) timer.Start();
49
50 const v8::StartupData* blob = isolate->snapshot_blob();
51 Vector<const byte> startup_data = ExtractStartupData(blob);
52 SnapshotData snapshot_data(startup_data);
53 Deserializer deserializer(&snapshot_data);
54 bool success = isolate->Init(&deserializer);
55 if (FLAG_profile_deserialization) {
56 double ms = timer.Elapsed().InMillisecondsF();
57 int bytes = startup_data.length();
58 PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
59 }
60 return success;
61}
62
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000063MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
Ben Murdoch61f157c2016-09-16 13:49:30 +010064 Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
65 size_t context_index) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066 if (!isolate->snapshot_available()) return Handle<Context>();
67 base::ElapsedTimer timer;
68 if (FLAG_profile_deserialization) timer.Start();
69
70 const v8::StartupData* blob = isolate->snapshot_blob();
Ben Murdoch61f157c2016-09-16 13:49:30 +010071 Vector<const byte> context_data =
72 ExtractContextData(blob, static_cast<int>(context_index));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000073 SnapshotData snapshot_data(context_data);
74 Deserializer deserializer(&snapshot_data);
75
76 MaybeHandle<Object> maybe_context =
77 deserializer.DeserializePartial(isolate, global_proxy);
78 Handle<Object> result;
79 if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
80 CHECK(result->IsContext());
81 if (FLAG_profile_deserialization) {
82 double ms = timer.Elapsed().InMillisecondsF();
83 int bytes = context_data.length();
Ben Murdoch61f157c2016-09-16 13:49:30 +010084 PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n",
85 context_index, bytes, ms);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000086 }
87 return Handle<Context>::cast(result);
88}
89
Ben Murdoch61f157c2016-09-16 13:49:30 +010090void UpdateMaxRequirementPerPage(
91 uint32_t* requirements,
92 Vector<const SerializedData::Reservation> reservations) {
93 int space = 0;
94 uint32_t current_requirement = 0;
95 for (const auto& reservation : reservations) {
96 current_requirement += reservation.chunk_size();
97 if (reservation.is_last()) {
98 requirements[space] = std::max(requirements[space], current_requirement);
99 current_requirement = 0;
100 space++;
101 }
102 }
103 DCHECK_EQ(i::Serializer::kNumberOfSpaces, space);
104}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000105
Ben Murdoch61f157c2016-09-16 13:49:30 +0100106void CalculateFirstPageSizes(const SnapshotData* startup_snapshot,
107 const List<SnapshotData*>* context_snapshots,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000108 uint32_t* sizes_out) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000109 if (FLAG_profile_deserialization) {
110 int startup_total = 0;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100111 PrintF("Deserialization will reserve:\n");
112 for (const auto& reservation : startup_snapshot->Reservations()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000113 startup_total += reservation.chunk_size();
114 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100115 PrintF("%10d bytes per isolate\n", startup_total);
116 for (int i = 0; i < context_snapshots->length(); i++) {
117 int context_total = 0;
118 for (const auto& reservation : context_snapshots->at(i)->Reservations()) {
119 context_total += reservation.chunk_size();
120 }
121 PrintF("%10d bytes per context #%d\n", context_total, i);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100123 }
124
125 uint32_t startup_requirements[i::Serializer::kNumberOfSpaces];
126 uint32_t context_requirements[i::Serializer::kNumberOfSpaces];
127 for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
128 startup_requirements[space] = 0;
129 context_requirements[space] = 0;
130 }
131
132 UpdateMaxRequirementPerPage(startup_requirements,
133 startup_snapshot->Reservations());
134 for (const auto& context_snapshot : *context_snapshots) {
135 UpdateMaxRequirementPerPage(context_requirements,
136 context_snapshot->Reservations());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 }
138
139 for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100140 // If the space requirement for a page is less than a page size, we consider
141 // limiting the size of the first page in order to save memory on startup.
142 uint32_t required = startup_requirements[space] +
143 2 * context_requirements[space] +
144 Page::kObjectStartOffset;
145 // Add a small allowance to the code space for small scripts.
146 if (space == CODE_SPACE) required += 32 * KB;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000147
148 if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) {
149 uint32_t max_size =
150 MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space));
Ben Murdoch61f157c2016-09-16 13:49:30 +0100151 sizes_out[space - FIRST_PAGED_SPACE] = std::min(required, max_size);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000152 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000153 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000154}
155
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000156v8::StartupData Snapshot::CreateSnapshotBlob(
Ben Murdoch61f157c2016-09-16 13:49:30 +0100157 const SnapshotData* startup_snapshot,
158 const List<SnapshotData*>* context_snapshots) {
159 int num_contexts = context_snapshots->length();
160 int startup_snapshot_offset = StartupSnapshotOffset(num_contexts);
161 int total_length = startup_snapshot_offset;
162 total_length += startup_snapshot->RawData().length();
163 for (const auto& context_snapshot : *context_snapshots) {
164 total_length += context_snapshot->RawData().length();
165 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000166
167 uint32_t first_page_sizes[kNumPagedSpaces];
Ben Murdoch61f157c2016-09-16 13:49:30 +0100168 CalculateFirstPageSizes(startup_snapshot, context_snapshots,
169 first_page_sizes);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000170
Ben Murdoch61f157c2016-09-16 13:49:30 +0100171 char* data = new char[total_length];
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000172 memcpy(data + kFirstPageSizesOffset, first_page_sizes,
173 kNumPagedSpaces * kInt32Size);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100174 memcpy(data + kNumberOfContextsOffset, &num_contexts, kInt32Size);
175 int payload_offset = StartupSnapshotOffset(num_contexts);
176 int payload_length = startup_snapshot->RawData().length();
177 memcpy(data + payload_offset, startup_snapshot->RawData().start(),
178 payload_length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179 if (FLAG_profile_deserialization) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100180 PrintF("Snapshot blob consists of:\n%10d bytes for startup\n",
181 payload_length);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000182 }
Ben Murdoch61f157c2016-09-16 13:49:30 +0100183 payload_offset += payload_length;
184 for (int i = 0; i < num_contexts; i++) {
185 memcpy(data + ContextSnapshotOffsetOffset(i), &payload_offset, kInt32Size);
186 SnapshotData* context_snapshot = context_snapshots->at(i);
187 payload_length = context_snapshot->RawData().length();
188 memcpy(data + payload_offset, context_snapshot->RawData().start(),
189 payload_length);
190 if (FLAG_profile_deserialization) {
191 PrintF("%10d bytes for context #%d\n", payload_length, i);
192 }
193 payload_offset += payload_length;
194 }
195
196 v8::StartupData result = {data, total_length};
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000197 return result;
198}
199
Ben Murdoch61f157c2016-09-16 13:49:30 +0100200int Snapshot::ExtractNumContexts(const v8::StartupData* data) {
201 CHECK_LT(kNumberOfContextsOffset, data->raw_size);
202 int num_contexts;
203 memcpy(&num_contexts, data->data + kNumberOfContextsOffset, kInt32Size);
204 return num_contexts;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205}
206
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000207Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100208 int num_contexts = ExtractNumContexts(data);
209 int startup_offset = StartupSnapshotOffset(num_contexts);
210 CHECK_LT(startup_offset, data->raw_size);
211 int first_context_offset;
212 memcpy(&first_context_offset, data->data + ContextSnapshotOffsetOffset(0),
213 kInt32Size);
214 CHECK_LT(first_context_offset, data->raw_size);
215 int startup_length = first_context_offset - startup_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000216 const byte* startup_data =
Ben Murdoch61f157c2016-09-16 13:49:30 +0100217 reinterpret_cast<const byte*>(data->data + startup_offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000218 return Vector<const byte>(startup_data, startup_length);
219}
220
Ben Murdoch61f157c2016-09-16 13:49:30 +0100221Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
222 int index) {
223 int num_contexts = ExtractNumContexts(data);
224 CHECK_LT(index, num_contexts);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225
Ben Murdoch61f157c2016-09-16 13:49:30 +0100226 int context_offset;
227 memcpy(&context_offset, data->data + ContextSnapshotOffsetOffset(index),
228 kInt32Size);
229 int next_context_offset;
230 if (index == num_contexts - 1) {
231 next_context_offset = data->raw_size;
232 } else {
233 memcpy(&next_context_offset,
234 data->data + ContextSnapshotOffsetOffset(index + 1), kInt32Size);
235 CHECK_LT(next_context_offset, data->raw_size);
236 }
237
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 const byte* context_data =
239 reinterpret_cast<const byte*>(data->data + context_offset);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100240 int context_length = next_context_offset - context_offset;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000241 return Vector<const byte>(context_data, context_length);
242}
Ben Murdochda12d292016-06-02 14:46:10 +0100243
Ben Murdoch61f157c2016-09-16 13:49:30 +0100244SnapshotData::SnapshotData(const Serializer* serializer) {
Ben Murdochda12d292016-06-02 14:46:10 +0100245 DisallowHeapAllocation no_gc;
246 List<Reservation> reservations;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100247 serializer->EncodeReservations(&reservations);
248 const List<byte>* payload = serializer->sink()->data();
Ben Murdochda12d292016-06-02 14:46:10 +0100249
250 // Calculate sizes.
251 int reservation_size = reservations.length() * kInt32Size;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100252 int size = kHeaderSize + reservation_size + payload->length();
Ben Murdochda12d292016-06-02 14:46:10 +0100253
254 // Allocate backing store and create result data.
255 AllocateData(size);
256
257 // Set header values.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100258 SetMagicNumber(serializer->isolate());
Ben Murdochda12d292016-06-02 14:46:10 +0100259 SetHeaderValue(kCheckSumOffset, Version::Hash());
260 SetHeaderValue(kNumReservationsOffset, reservations.length());
Ben Murdoch61f157c2016-09-16 13:49:30 +0100261 SetHeaderValue(kPayloadLengthOffset, payload->length());
Ben Murdochda12d292016-06-02 14:46:10 +0100262
263 // Copy reservation chunk sizes.
264 CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
265 reservation_size);
266
267 // Copy serialized data.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100268 CopyBytes(data_ + kHeaderSize + reservation_size, payload->begin(),
269 static_cast<size_t>(payload->length()));
Ben Murdochda12d292016-06-02 14:46:10 +0100270}
271
272bool SnapshotData::IsSane() {
273 return GetHeaderValue(kCheckSumOffset) == Version::Hash();
274}
275
276Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
277 return Vector<const Reservation>(
278 reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
279 GetHeaderValue(kNumReservationsOffset));
280}
281
282Vector<const byte> SnapshotData::Payload() const {
283 int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size;
284 const byte* payload = data_ + kHeaderSize + reservations_size;
285 int length = GetHeaderValue(kPayloadLengthOffset);
286 DCHECK_EQ(data_ + size_, payload + length);
287 return Vector<const byte>(payload, length);
288}
289
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000290} // namespace internal
291} // namespace v8