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 20 bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) { 21 return Snapshot::ExtractNumContexts(snapshot_blob) > 0; 22 } 23 #endif // DEBUG 24 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 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 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 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 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 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 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 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 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 210 bool SnapshotData::IsSane() { 211 return GetHeaderValue(kCheckSumOffset) == Version::Hash(); 212 } 213 214 Vector<const SerializedData::Reservation> SnapshotData::Reservations() const { 215 return Vector<const Reservation>( 216 reinterpret_cast<const Reservation*>(data_ + kHeaderSize), 217 GetHeaderValue(kNumReservationsOffset)); 218 } 219 220 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