| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // The common functionality when building with or without snapshots. | 5 // The common functionality when building with or without snapshots. |
| 6 | 6 |
| 7 #include "src/snapshot/snapshot.h" | 7 #include "src/snapshot/snapshot.h" |
| 8 | 8 |
| 9 #include "src/api.h" | 9 #include "src/api.h" |
| 10 #include "src/base/platform/platform.h" | 10 #include "src/base/platform/platform.h" |
| 11 #include "src/full-codegen/full-codegen.h" | 11 #include "src/full-codegen/full-codegen.h" |
| 12 #include "src/snapshot/deserializer.h" | 12 #include "src/snapshot/deserializer.h" |
| 13 #include "src/snapshot/snapshot-source-sink.h" | 13 #include "src/snapshot/snapshot-source-sink.h" |
| 14 #include "src/version.h" | 14 #include "src/version.h" |
| 15 | 15 |
| 16 namespace v8 { | 16 namespace v8 { |
| 17 namespace internal { | 17 namespace internal { |
| 18 | 18 |
| 19 #ifdef DEBUG | 19 #ifdef DEBUG |
| 20 bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) { | 20 bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) { |
| 21 return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() && | 21 return Snapshot::ExtractNumContexts(snapshot_blob) > 0; |
| 22 !Snapshot::ExtractContextData(snapshot_blob).is_empty(); | |
| 23 } | 22 } |
| 24 #endif // DEBUG | 23 #endif // DEBUG |
| 25 | 24 |
| 26 | 25 |
| 27 bool Snapshot::HaveASnapshotToStartFrom(Isolate* isolate) { | 26 bool Snapshot::HaveASnapshotToStartFrom(Isolate* isolate) { |
| 28 // Do not use snapshots if the isolate is used to create snapshots. | 27 // Do not use snapshots if the isolate is used to create snapshots. |
| 29 return isolate->snapshot_blob() != NULL && | 28 return isolate->snapshot_blob() != NULL && |
| 30 isolate->snapshot_blob()->data != NULL; | 29 isolate->snapshot_blob()->data != NULL; |
| 31 } | 30 } |
| 32 | 31 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 54 Deserializer deserializer(&snapshot_data); | 53 Deserializer deserializer(&snapshot_data); |
| 55 bool success = isolate->Init(&deserializer); | 54 bool success = isolate->Init(&deserializer); |
| 56 if (FLAG_profile_deserialization) { | 55 if (FLAG_profile_deserialization) { |
| 57 double ms = timer.Elapsed().InMillisecondsF(); | 56 double ms = timer.Elapsed().InMillisecondsF(); |
| 58 int bytes = startup_data.length(); | 57 int bytes = startup_data.length(); |
| 59 PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms); | 58 PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms); |
| 60 } | 59 } |
| 61 return success; | 60 return success; |
| 62 } | 61 } |
| 63 | 62 |
| 64 | |
| 65 MaybeHandle<Context> Snapshot::NewContextFromSnapshot( | 63 MaybeHandle<Context> Snapshot::NewContextFromSnapshot( |
| 66 Isolate* isolate, Handle<JSGlobalProxy> global_proxy) { | 64 Isolate* isolate, Handle<JSGlobalProxy> global_proxy, |
| 65 size_t context_index) { |
| 67 if (!isolate->snapshot_available()) return Handle<Context>(); | 66 if (!isolate->snapshot_available()) return Handle<Context>(); |
| 68 base::ElapsedTimer timer; | 67 base::ElapsedTimer timer; |
| 69 if (FLAG_profile_deserialization) timer.Start(); | 68 if (FLAG_profile_deserialization) timer.Start(); |
| 70 | 69 |
| 71 const v8::StartupData* blob = isolate->snapshot_blob(); | 70 const v8::StartupData* blob = isolate->snapshot_blob(); |
| 72 Vector<const byte> context_data = ExtractContextData(blob); | 71 Vector<const byte> context_data = |
| 72 ExtractContextData(blob, static_cast<int>(context_index)); |
| 73 SnapshotData snapshot_data(context_data); | 73 SnapshotData snapshot_data(context_data); |
| 74 Deserializer deserializer(&snapshot_data); | 74 Deserializer deserializer(&snapshot_data); |
| 75 | 75 |
| 76 MaybeHandle<Object> maybe_context = | 76 MaybeHandle<Object> maybe_context = |
| 77 deserializer.DeserializePartial(isolate, global_proxy); | 77 deserializer.DeserializePartial(isolate, global_proxy); |
| 78 Handle<Object> result; | 78 Handle<Object> result; |
| 79 if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>(); | 79 if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>(); |
| 80 CHECK(result->IsContext()); | 80 CHECK(result->IsContext()); |
| 81 if (FLAG_profile_deserialization) { | 81 if (FLAG_profile_deserialization) { |
| 82 double ms = timer.Elapsed().InMillisecondsF(); | 82 double ms = timer.Elapsed().InMillisecondsF(); |
| 83 int bytes = context_data.length(); | 83 int bytes = context_data.length(); |
| 84 PrintF("[Deserializing context (%d bytes) took %0.3f ms]\n", bytes, ms); | 84 PrintF("[Deserializing context #%zu (%d bytes) took %0.3f ms]\n", |
| 85 context_index, bytes, ms); |
| 85 } | 86 } |
| 86 return Handle<Context>::cast(result); | 87 return Handle<Context>::cast(result); |
| 87 } | 88 } |
| 88 | 89 |
| 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 |
| 89 void CalculateFirstPageSizes(const SnapshotData* startup_snapshot, | 106 void CalculateFirstPageSizes(const SnapshotData* startup_snapshot, |
| 90 const SnapshotData* context_snapshot, | 107 const List<SnapshotData*>* context_snapshots, |
| 91 uint32_t* sizes_out) { | 108 uint32_t* sizes_out) { |
| 92 Vector<const SerializedData::Reservation> startup_reservations = | |
| 93 startup_snapshot->Reservations(); | |
| 94 Vector<const SerializedData::Reservation> context_reservations = | |
| 95 context_snapshot->Reservations(); | |
| 96 int startup_index = 0; | |
| 97 int context_index = 0; | |
| 98 | |
| 99 if (FLAG_profile_deserialization) { | 109 if (FLAG_profile_deserialization) { |
| 100 int startup_total = 0; | 110 int startup_total = 0; |
| 101 int context_total = 0; | 111 PrintF("Deserialization will reserve:\n"); |
| 102 for (const auto& reservation : startup_reservations) { | 112 for (const auto& reservation : startup_snapshot->Reservations()) { |
| 103 startup_total += reservation.chunk_size(); | 113 startup_total += reservation.chunk_size(); |
| 104 } | 114 } |
| 105 for (const auto& reservation : context_reservations) { | 115 PrintF("%10d bytes per isolate\n", startup_total); |
| 106 context_total += reservation.chunk_size(); | 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); |
| 107 } | 122 } |
| 108 PrintF( | 123 } |
| 109 "Deserialization will reserve:\n" | 124 |
| 110 "%10d bytes per isolate\n" | 125 uint32_t startup_requirements[i::Serializer::kNumberOfSpaces]; |
| 111 "%10d bytes per context\n", | 126 uint32_t context_requirements[i::Serializer::kNumberOfSpaces]; |
| 112 startup_total, context_total); | 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()); |
| 113 } | 137 } |
| 114 | 138 |
| 115 for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) { | 139 for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) { |
| 116 bool single_chunk = true; | 140 // If the space requirement for a page is less than a page size, we consider |
| 117 while (!startup_reservations[startup_index].is_last()) { | 141 // limiting the size of the first page in order to save memory on startup. |
| 118 single_chunk = false; | 142 uint32_t required = startup_requirements[space] + |
| 119 startup_index++; | 143 2 * context_requirements[space] + |
| 120 } | 144 Page::kObjectStartOffset; |
| 121 while (!context_reservations[context_index].is_last()) { | 145 // Add a small allowance to the code space for small scripts. |
| 122 single_chunk = false; | 146 if (space == CODE_SPACE) required += 32 * KB; |
| 123 context_index++; | |
| 124 } | |
| 125 | |
| 126 uint32_t required = kMaxUInt32; | |
| 127 if (single_chunk) { | |
| 128 // If both the startup snapshot data and the context snapshot data on | |
| 129 // this space fit in a single page, then we consider limiting the size | |
| 130 // of the first page. For this, we add the chunk sizes and some extra | |
| 131 // allowance. This way we achieve a smaller startup memory footprint. | |
| 132 required = (startup_reservations[startup_index].chunk_size() + | |
| 133 2 * context_reservations[context_index].chunk_size()) + | |
| 134 Page::kObjectStartOffset; | |
| 135 // Add a small allowance to the code space for small scripts. | |
| 136 if (space == CODE_SPACE) required += 32 * KB; | |
| 137 } | |
| 138 | 147 |
| 139 if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) { | 148 if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) { |
| 140 uint32_t max_size = | 149 uint32_t max_size = |
| 141 MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space)); | 150 MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space)); |
| 142 sizes_out[space - FIRST_PAGED_SPACE] = Min(required, max_size); | 151 sizes_out[space - FIRST_PAGED_SPACE] = std::min(required, max_size); |
| 143 } else { | |
| 144 DCHECK(single_chunk); | |
| 145 } | 152 } |
| 146 startup_index++; | |
| 147 context_index++; | |
| 148 } | 153 } |
| 149 | |
| 150 DCHECK_EQ(startup_reservations.length(), startup_index); | |
| 151 DCHECK_EQ(context_reservations.length(), context_index); | |
| 152 } | 154 } |
| 153 | 155 |
| 154 v8::StartupData Snapshot::CreateSnapshotBlob( | 156 v8::StartupData Snapshot::CreateSnapshotBlob( |
| 155 const StartupSerializer* startup_serializer, | 157 const SnapshotData* startup_snapshot, |
| 156 const PartialSerializer* context_serializer) { | 158 const List<SnapshotData*>* context_snapshots) { |
| 157 SnapshotData startup_snapshot(startup_serializer); | 159 int num_contexts = context_snapshots->length(); |
| 158 SnapshotData context_snapshot(context_serializer); | 160 int startup_snapshot_offset = StartupSnapshotOffset(num_contexts); |
| 159 Vector<const byte> startup_data = startup_snapshot.RawData(); | 161 int total_length = startup_snapshot_offset; |
| 160 Vector<const byte> context_data = context_snapshot.RawData(); | 162 total_length += startup_snapshot->RawData().length(); |
| 163 for (const auto& context_snapshot : *context_snapshots) { |
| 164 total_length += context_snapshot->RawData().length(); |
| 165 } |
| 161 | 166 |
| 162 uint32_t first_page_sizes[kNumPagedSpaces]; | 167 uint32_t first_page_sizes[kNumPagedSpaces]; |
| 163 | 168 CalculateFirstPageSizes(startup_snapshot, context_snapshots, |
| 164 CalculateFirstPageSizes(&startup_snapshot, &context_snapshot, | |
| 165 first_page_sizes); | 169 first_page_sizes); |
| 166 | 170 |
| 167 int startup_length = startup_data.length(); | 171 char* data = new char[total_length]; |
| 168 int context_length = context_data.length(); | |
| 169 int context_offset = ContextOffset(startup_length); | |
| 170 | |
| 171 int length = context_offset + context_length; | |
| 172 char* data = new char[length]; | |
| 173 | |
| 174 memcpy(data + kFirstPageSizesOffset, first_page_sizes, | 172 memcpy(data + kFirstPageSizesOffset, first_page_sizes, |
| 175 kNumPagedSpaces * kInt32Size); | 173 kNumPagedSpaces * kInt32Size); |
| 176 memcpy(data + kStartupLengthOffset, &startup_length, kInt32Size); | 174 memcpy(data + kNumberOfContextsOffset, &num_contexts, kInt32Size); |
| 177 memcpy(data + kStartupDataOffset, startup_data.begin(), startup_length); | 175 int payload_offset = StartupSnapshotOffset(num_contexts); |
| 178 memcpy(data + context_offset, context_data.begin(), context_length); | 176 int payload_length = startup_snapshot->RawData().length(); |
| 179 v8::StartupData result = {data, 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 } |
| 180 | 195 |
| 181 if (FLAG_profile_deserialization) { | 196 v8::StartupData result = {data, total_length}; |
| 182 PrintF( | |
| 183 "Snapshot blob consists of:\n" | |
| 184 "%10d bytes for startup\n" | |
| 185 "%10d bytes for context\n", | |
| 186 startup_length, context_length); | |
| 187 } | |
| 188 return result; | 197 return result; |
| 189 } | 198 } |
| 190 | 199 |
| 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 |
| 191 Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) { | 207 Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) { |
| 192 DCHECK_LT(kIntSize, data->raw_size); | 208 int num_contexts = ExtractNumContexts(data); |
| 193 int startup_length; | 209 int startup_offset = StartupSnapshotOffset(num_contexts); |
| 194 memcpy(&startup_length, data->data + kStartupLengthOffset, kInt32Size); | 210 CHECK_LT(startup_offset, data->raw_size); |
| 195 DCHECK_LT(startup_length, 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; |
| 196 const byte* startup_data = | 216 const byte* startup_data = |
| 197 reinterpret_cast<const byte*>(data->data + kStartupDataOffset); | 217 reinterpret_cast<const byte*>(data->data + startup_offset); |
| 198 return Vector<const byte>(startup_data, startup_length); | 218 return Vector<const byte>(startup_data, startup_length); |
| 199 } | 219 } |
| 200 | 220 |
| 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); |
| 201 | 225 |
| 202 Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data) { | 226 int context_offset; |
| 203 DCHECK_LT(kIntSize, data->raw_size); | 227 memcpy(&context_offset, data->data + ContextSnapshotOffsetOffset(index), |
| 204 int startup_length; | 228 kInt32Size); |
| 205 memcpy(&startup_length, data->data + kStartupLengthOffset, kIntSize); | 229 int next_context_offset; |
| 206 int context_offset = ContextOffset(startup_length); | 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 |
| 207 const byte* context_data = | 238 const byte* context_data = |
| 208 reinterpret_cast<const byte*>(data->data + context_offset); | 239 reinterpret_cast<const byte*>(data->data + context_offset); |
| 209 DCHECK_LT(context_offset, data->raw_size); | 240 int context_length = next_context_offset - context_offset; |
| 210 int context_length = data->raw_size - context_offset; | |
| 211 return Vector<const byte>(context_data, context_length); | 241 return Vector<const byte>(context_data, context_length); |
| 212 } | 242 } |
| 213 | 243 |
| 214 SnapshotData::SnapshotData(const Serializer* serializer) { | 244 SnapshotData::SnapshotData(const Serializer* serializer) { |
| 215 DisallowHeapAllocation no_gc; | 245 DisallowHeapAllocation no_gc; |
| 216 List<Reservation> reservations; | 246 List<Reservation> reservations; |
| 217 serializer->EncodeReservations(&reservations); | 247 serializer->EncodeReservations(&reservations); |
| 218 const List<byte>* payload = serializer->sink()->data(); | 248 const List<byte>* payload = serializer->sink()->data(); |
| 219 | 249 |
| 220 // Calculate sizes. | 250 // Calculate sizes. |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 Vector<const byte> SnapshotData::Payload() const { | 282 Vector<const byte> SnapshotData::Payload() const { |
| 253 int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size; | 283 int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size; |
| 254 const byte* payload = data_ + kHeaderSize + reservations_size; | 284 const byte* payload = data_ + kHeaderSize + reservations_size; |
| 255 int length = GetHeaderValue(kPayloadLengthOffset); | 285 int length = GetHeaderValue(kPayloadLengthOffset); |
| 256 DCHECK_EQ(data_ + size_, payload + length); | 286 DCHECK_EQ(data_ + size_, payload + length); |
| 257 return Vector<const byte>(payload, length); | 287 return Vector<const byte>(payload, length); |
| 258 } | 288 } |
| 259 | 289 |
| 260 } // namespace internal | 290 } // namespace internal |
| 261 } // namespace v8 | 291 } // namespace v8 |
| OLD | NEW |