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