• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/snapshot/deserializer.h"
13 #include "src/snapshot/snapshot-source-sink.h"
14 #include "src/version.h"
15 
16 namespace v8 {
17 namespace internal {
18 
19 #ifdef DEBUG
SnapshotIsValid(v8::StartupData * snapshot_blob)20 bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
21   return Snapshot::ExtractNumContexts(snapshot_blob) > 0;
22 }
23 #endif  // DEBUG
24 
25 
HaveASnapshotToStartFrom(Isolate * isolate)26 bool 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 
SizeOfFirstPage(Isolate * isolate,AllocationSpace space)33 uint32_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 
Initialize(Isolate * isolate)45 bool 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 
NewContextFromSnapshot(Isolate * isolate,Handle<JSGlobalProxy> global_proxy,size_t context_index)63 MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
64     Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
65     size_t context_index) {
66   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();
71   Vector<const byte> context_data =
72       ExtractContextData(blob, static_cast<int>(context_index));
73   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();
84     PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n",
85            context_index, bytes, ms);
86   }
87   return Handle<Context>::cast(result);
88 }
89 
UpdateMaxRequirementPerPage(uint32_t * requirements,Vector<const SerializedData::Reservation> reservations)90 void 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 }
105 
CalculateFirstPageSizes(const SnapshotData * startup_snapshot,const List<SnapshotData * > * context_snapshots,uint32_t * sizes_out)106 void CalculateFirstPageSizes(const SnapshotData* startup_snapshot,
107                              const List<SnapshotData*>* context_snapshots,
108                              uint32_t* sizes_out) {
109   if (FLAG_profile_deserialization) {
110     int startup_total = 0;
111     PrintF("Deserialization will reserve:\n");
112     for (const auto& reservation : startup_snapshot->Reservations()) {
113       startup_total += reservation.chunk_size();
114     }
115     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);
122     }
123   }
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());
137   }
138 
139   for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
140     // 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;
147 
148     if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) {
149       uint32_t max_size =
150           MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space));
151       sizes_out[space - FIRST_PAGED_SPACE] = std::min(required, max_size);
152     }
153   }
154 }
155 
CreateSnapshotBlob(const SnapshotData * startup_snapshot,const List<SnapshotData * > * context_snapshots)156 v8::StartupData Snapshot::CreateSnapshotBlob(
157     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   }
166 
167   uint32_t first_page_sizes[kNumPagedSpaces];
168   CalculateFirstPageSizes(startup_snapshot, context_snapshots,
169                           first_page_sizes);
170 
171   char* data = new char[total_length];
172   memcpy(data + kFirstPageSizesOffset, first_page_sizes,
173          kNumPagedSpaces * kInt32Size);
174   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);
179   if (FLAG_profile_deserialization) {
180     PrintF("Snapshot blob consists of:\n%10d bytes for startup\n",
181            payload_length);
182   }
183   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};
197   return result;
198 }
199 
ExtractNumContexts(const v8::StartupData * data)200 int 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;
205 }
206 
ExtractStartupData(const v8::StartupData * data)207 Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
208   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;
216   const byte* startup_data =
217       reinterpret_cast<const byte*>(data->data + startup_offset);
218   return Vector<const byte>(startup_data, startup_length);
219 }
220 
ExtractContextData(const v8::StartupData * data,int index)221 Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data,
222                                                 int index) {
223   int num_contexts = ExtractNumContexts(data);
224   CHECK_LT(index, num_contexts);
225 
226   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 
238   const byte* context_data =
239       reinterpret_cast<const byte*>(data->data + context_offset);
240   int context_length = next_context_offset - context_offset;
241   return Vector<const byte>(context_data, context_length);
242 }
243 
SnapshotData(const Serializer * serializer)244 SnapshotData::SnapshotData(const Serializer* serializer) {
245   DisallowHeapAllocation no_gc;
246   List<Reservation> reservations;
247   serializer->EncodeReservations(&reservations);
248   const List<byte>* payload = serializer->sink()->data();
249 
250   // Calculate sizes.
251   int reservation_size = reservations.length() * kInt32Size;
252   int size = kHeaderSize + reservation_size + payload->length();
253 
254   // Allocate backing store and create result data.
255   AllocateData(size);
256 
257   // Set header values.
258   SetMagicNumber(serializer->isolate());
259   SetHeaderValue(kCheckSumOffset, Version::Hash());
260   SetHeaderValue(kNumReservationsOffset, reservations.length());
261   SetHeaderValue(kPayloadLengthOffset, payload->length());
262 
263   // Copy reservation chunk sizes.
264   CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()),
265             reservation_size);
266 
267   // Copy serialized data.
268   CopyBytes(data_ + kHeaderSize + reservation_size, payload->begin(),
269             static_cast<size_t>(payload->length()));
270 }
271 
IsSane()272 bool SnapshotData::IsSane() {
273   return GetHeaderValue(kCheckSumOffset) == Version::Hash();
274 }
275 
Reservations() const276 Vector<const SerializedData::Reservation> SnapshotData::Reservations() const {
277   return Vector<const Reservation>(
278       reinterpret_cast<const Reservation*>(data_ + kHeaderSize),
279       GetHeaderValue(kNumReservationsOffset));
280 }
281 
Payload() const282 Vector<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 
290 }  // namespace internal
291 }  // namespace v8
292