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