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 |