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