OLD | NEW |
---|---|
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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 #include "src/snapshot/code-serializer.h" | 5 #include "src/snapshot/code-serializer.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/log.h" | 10 #include "src/log.h" |
11 #include "src/macro-assembler.h" | 11 #include "src/macro-assembler.h" |
12 #include "src/snapshot/deserializer.h" | 12 #include "src/snapshot/deserializer.h" |
13 #include "src/snapshot/snapshot.h" | |
13 #include "src/version.h" | 14 #include "src/version.h" |
14 | 15 |
15 namespace v8 { | 16 namespace v8 { |
16 namespace internal { | 17 namespace internal { |
17 | 18 |
18 ScriptData* CodeSerializer::Serialize(Isolate* isolate, | 19 ScriptData* CodeSerializer::Serialize(Isolate* isolate, |
19 Handle<SharedFunctionInfo> info, | 20 Handle<SharedFunctionInfo> info, |
20 Handle<String> source) { | 21 Handle<String> source) { |
21 base::ElapsedTimer timer; | 22 base::ElapsedTimer timer; |
22 if (FLAG_profile_deserialization) timer.Start(); | 23 if (FLAG_profile_deserialization) timer.Start(); |
23 if (FLAG_trace_serializer) { | 24 if (FLAG_trace_serializer) { |
24 PrintF("[Serializing from"); | 25 PrintF("[Serializing from"); |
25 Object* script = info->script(); | 26 Object* script = info->script(); |
26 if (script->IsScript()) Script::cast(script)->name()->ShortPrint(); | 27 if (script->IsScript()) Script::cast(script)->name()->ShortPrint(); |
27 PrintF("]\n"); | 28 PrintF("]\n"); |
28 } | 29 } |
29 | 30 |
30 // Serialize code object. | 31 // Serialize code object. |
31 CodeSerializer cs(isolate, *source); | 32 CodeSerializer cs(isolate, SerializedCodeData::SourceHash(source)); |
32 DisallowHeapAllocation no_gc; | 33 DisallowHeapAllocation no_gc; |
33 Object** location = Handle<Object>::cast(info).location(); | 34 cs.reference_map()->AddAttachedReference(*source); |
34 cs.VisitPointer(location); | 35 ScriptData* ret = cs.Serialize(info); |
35 cs.SerializeDeferredObjects(); | |
36 cs.Pad(); | |
37 | |
38 SerializedCodeData data(cs.sink()->data(), &cs); | |
39 ScriptData* script_data = data.GetScriptData(); | |
40 | 36 |
41 if (FLAG_profile_deserialization) { | 37 if (FLAG_profile_deserialization) { |
42 double ms = timer.Elapsed().InMillisecondsF(); | 38 double ms = timer.Elapsed().InMillisecondsF(); |
43 int length = script_data->length(); | 39 int length = ret->length(); |
44 PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms); | 40 PrintF("[Serializing to %d bytes took %0.3f ms]\n", length, ms); |
45 } | 41 } |
46 | 42 |
47 return script_data; | 43 return ret; |
44 } | |
45 | |
46 ScriptData* CodeSerializer::Serialize(Handle<HeapObject> obj) { | |
47 DisallowHeapAllocation no_gc; | |
48 | |
49 VisitPointer(Handle<Object>::cast(obj).location()); | |
50 SerializeDeferredObjects(); | |
51 Pad(); | |
52 | |
53 SerializedCodeData data(sink()->data(), this); | |
54 | |
55 return data.GetScriptData(); | |
48 } | 56 } |
49 | 57 |
50 void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, | 58 void CodeSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, |
51 WhereToPoint where_to_point, int skip) { | 59 WhereToPoint where_to_point, int skip) { |
52 if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return; | 60 if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return; |
53 | 61 |
54 int root_index = root_index_map_.Lookup(obj); | 62 int root_index = root_index_map_.Lookup(obj); |
55 if (root_index != RootIndexMap::kInvalidRootIndex) { | 63 if (root_index != RootIndexMap::kInvalidRootIndex) { |
56 PutRoot(root_index, obj, how_to_code, where_to_point, skip); | 64 PutRoot(root_index, obj, how_to_code, where_to_point, skip); |
57 return; | 65 return; |
(...skipping 22 matching lines...) Expand all Loading... | |
80 #undef IC_KIND_CASE | 88 #undef IC_KIND_CASE |
81 SerializeCodeStub(code_object, how_to_code, where_to_point); | 89 SerializeCodeStub(code_object, how_to_code, where_to_point); |
82 return; | 90 return; |
83 case Code::FUNCTION: | 91 case Code::FUNCTION: |
84 DCHECK(code_object->has_reloc_info_for_serialization()); | 92 DCHECK(code_object->has_reloc_info_for_serialization()); |
85 SerializeGeneric(code_object, how_to_code, where_to_point); | 93 SerializeGeneric(code_object, how_to_code, where_to_point); |
86 return; | 94 return; |
87 case Code::WASM_FUNCTION: | 95 case Code::WASM_FUNCTION: |
88 case Code::WASM_TO_JS_FUNCTION: | 96 case Code::WASM_TO_JS_FUNCTION: |
89 case Code::JS_TO_WASM_FUNCTION: | 97 case Code::JS_TO_WASM_FUNCTION: |
90 UNREACHABLE(); | 98 SerializeGeneric(code_object, how_to_code, where_to_point); |
Yang
2016/08/05 12:04:17
Would it make sense to check for code_object->has_
Yang
2016/08/05 12:05:44
Also, assuming that we will use a subclass of Code
Mircea Trofin
2016/08/05 15:01:29
We don't set that flag. Should we? It seems to be
Yang
2016/08/05 15:39:28
We don't emit reloc info for external references i
Mircea Trofin
2016/08/06 00:31:39
I see - thanks.
It turns out that has_reloc_code
| |
99 return; | |
91 } | 100 } |
92 UNREACHABLE(); | 101 UNREACHABLE(); |
93 } | 102 } |
94 | 103 |
95 // Past this point we should not see any (context-specific) maps anymore. | 104 // Past this point we should not see any (context-specific) maps anymore. |
96 CHECK(!obj->IsMap()); | 105 CHECK(!obj->IsMap()); |
97 // There should be no references to the global object embedded. | 106 // There should be no references to the global object embedded. |
98 CHECK(!obj->IsJSGlobalProxy() && !obj->IsJSGlobalObject()); | 107 CHECK(!obj->IsJSGlobalProxy() && !obj->IsJSGlobalObject()); |
99 // There should be no hash table embedded. They would require rehashing. | 108 // There should be no hash table embedded. They would require rehashing. |
100 CHECK(!obj->IsHashTable()); | 109 CHECK(!obj->IsHashTable()); |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
149 PutAttachedReference(reference, how_to_code, where_to_point); | 158 PutAttachedReference(reference, how_to_code, where_to_point); |
150 } | 159 } |
151 | 160 |
152 MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( | 161 MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( |
153 Isolate* isolate, ScriptData* cached_data, Handle<String> source) { | 162 Isolate* isolate, ScriptData* cached_data, Handle<String> source) { |
154 base::ElapsedTimer timer; | 163 base::ElapsedTimer timer; |
155 if (FLAG_profile_deserialization) timer.Start(); | 164 if (FLAG_profile_deserialization) timer.Start(); |
156 | 165 |
157 HandleScope scope(isolate); | 166 HandleScope scope(isolate); |
158 | 167 |
159 std::unique_ptr<SerializedCodeData> scd( | 168 SanityCheckResult sanity_check_result = CHECK_SUCCESS; |
160 SerializedCodeData::FromCachedData(isolate, cached_data, *source)); | 169 const SerializedCodeData scd = SerializedCodeData::FromCachedData( |
161 if (!scd) { | 170 isolate, cached_data, SerializedCodeData::SourceHash(source), |
171 &sanity_check_result); | |
172 if (sanity_check_result != CHECK_SUCCESS) { | |
162 if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n"); | 173 if (FLAG_profile_deserialization) PrintF("[Cached code failed check]\n"); |
163 DCHECK(cached_data->rejected()); | 174 DCHECK(cached_data->rejected()); |
175 source->GetIsolate()->counters()->code_cache_reject_reason()->AddSample( | |
176 sanity_check_result); | |
164 return MaybeHandle<SharedFunctionInfo>(); | 177 return MaybeHandle<SharedFunctionInfo>(); |
165 } | 178 } |
166 | 179 |
167 Deserializer deserializer(scd.get()); | 180 Deserializer deserializer(&scd); |
168 deserializer.AddAttachedObject(source); | 181 deserializer.AddAttachedObject(source); |
169 Vector<const uint32_t> code_stub_keys = scd->CodeStubKeys(); | 182 Vector<const uint32_t> code_stub_keys = scd.CodeStubKeys(); |
170 for (int i = 0; i < code_stub_keys.length(); i++) { | 183 for (int i = 0; i < code_stub_keys.length(); i++) { |
171 deserializer.AddAttachedObject( | 184 deserializer.AddAttachedObject( |
172 CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked()); | 185 CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked()); |
173 } | 186 } |
174 | 187 |
175 // Deserialize. | 188 // Deserialize. |
176 Handle<SharedFunctionInfo> result; | 189 Handle<HeapObject> as_heap_object; |
177 if (!deserializer.DeserializeCode(isolate).ToHandle(&result)) { | 190 if (!deserializer.DeserializeObject(isolate).ToHandle(&as_heap_object)) { |
178 // Deserializing may fail if the reservations cannot be fulfilled. | 191 // Deserializing may fail if the reservations cannot be fulfilled. |
179 if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n"); | 192 if (FLAG_profile_deserialization) PrintF("[Deserializing failed]\n"); |
180 return MaybeHandle<SharedFunctionInfo>(); | 193 return MaybeHandle<SharedFunctionInfo>(); |
181 } | 194 } |
182 | 195 |
196 Handle<SharedFunctionInfo> result = | |
197 Handle<SharedFunctionInfo>::cast(as_heap_object); | |
183 if (FLAG_profile_deserialization) { | 198 if (FLAG_profile_deserialization) { |
184 double ms = timer.Elapsed().InMillisecondsF(); | 199 double ms = timer.Elapsed().InMillisecondsF(); |
185 int length = cached_data->length(); | 200 int length = cached_data->length(); |
186 PrintF("[Deserializing from %d bytes took %0.3f ms]\n", length, ms); | 201 PrintF("[Deserializing from %d bytes took %0.3f ms]\n", length, ms); |
187 } | 202 } |
188 result->set_deserialized(true); | 203 result->set_deserialized(true); |
189 | 204 |
190 if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) { | 205 if (isolate->logger()->is_logging_code_events() || isolate->is_profiling()) { |
191 String* name = isolate->heap()->empty_string(); | 206 String* name = isolate->heap()->empty_string(); |
192 if (result->script()->IsScript()) { | 207 if (result->script()->IsScript()) { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
253 int payload_offset = kHeaderSize + reservation_size + stub_keys_size; | 268 int payload_offset = kHeaderSize + reservation_size + stub_keys_size; |
254 int padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset); | 269 int padded_payload_offset = POINTER_SIZE_ALIGN(payload_offset); |
255 int size = padded_payload_offset + payload->length(); | 270 int size = padded_payload_offset + payload->length(); |
256 | 271 |
257 // Allocate backing store and create result data. | 272 // Allocate backing store and create result data. |
258 AllocateData(size); | 273 AllocateData(size); |
259 | 274 |
260 // Set header values. | 275 // Set header values. |
261 SetMagicNumber(cs->isolate()); | 276 SetMagicNumber(cs->isolate()); |
262 SetHeaderValue(kVersionHashOffset, Version::Hash()); | 277 SetHeaderValue(kVersionHashOffset, Version::Hash()); |
263 SetHeaderValue(kSourceHashOffset, SourceHash(cs->source())); | 278 SetHeaderValue(kSourceHashOffset, cs->source_hash()); |
264 SetHeaderValue(kCpuFeaturesOffset, | 279 SetHeaderValue(kCpuFeaturesOffset, |
265 static_cast<uint32_t>(CpuFeatures::SupportedFeatures())); | 280 static_cast<uint32_t>(CpuFeatures::SupportedFeatures())); |
266 SetHeaderValue(kFlagHashOffset, FlagList::Hash()); | 281 SetHeaderValue(kFlagHashOffset, FlagList::Hash()); |
267 SetHeaderValue(kNumReservationsOffset, reservations.length()); | 282 SetHeaderValue(kNumReservationsOffset, reservations.length()); |
268 SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys); | 283 SetHeaderValue(kNumCodeStubKeysOffset, num_stub_keys); |
269 SetHeaderValue(kPayloadLengthOffset, payload->length()); | 284 SetHeaderValue(kPayloadLengthOffset, payload->length()); |
270 | 285 |
271 Checksum checksum(payload->ToConstVector()); | 286 Checksum checksum(payload->ToConstVector()); |
272 SetHeaderValue(kChecksum1Offset, checksum.a()); | 287 SetHeaderValue(kChecksum1Offset, checksum.a()); |
273 SetHeaderValue(kChecksum2Offset, checksum.b()); | 288 SetHeaderValue(kChecksum2Offset, checksum.b()); |
274 | 289 |
275 // Copy reservation chunk sizes. | 290 // Copy reservation chunk sizes. |
276 CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()), | 291 CopyBytes(data_ + kHeaderSize, reinterpret_cast<byte*>(reservations.begin()), |
277 reservation_size); | 292 reservation_size); |
278 | 293 |
279 // Copy code stub keys. | 294 // Copy code stub keys. |
280 CopyBytes(data_ + kHeaderSize + reservation_size, | 295 CopyBytes(data_ + kHeaderSize + reservation_size, |
281 reinterpret_cast<byte*>(stub_keys->begin()), stub_keys_size); | 296 reinterpret_cast<byte*>(stub_keys->begin()), stub_keys_size); |
282 | 297 |
283 memset(data_ + payload_offset, 0, padded_payload_offset - payload_offset); | 298 memset(data_ + payload_offset, 0, padded_payload_offset - payload_offset); |
284 | 299 |
285 // Copy serialized data. | 300 // Copy serialized data. |
286 CopyBytes(data_ + padded_payload_offset, payload->begin(), | 301 CopyBytes(data_ + padded_payload_offset, payload->begin(), |
287 static_cast<size_t>(payload->length())); | 302 static_cast<size_t>(payload->length())); |
288 } | 303 } |
289 | 304 |
290 SerializedCodeData::SanityCheckResult SerializedCodeData::SanityCheck( | 305 SanityCheckResult SerializedCodeData::SanityCheck( |
291 Isolate* isolate, String* source) const { | 306 Isolate* isolate, uint32_t expected_source_hash) const { |
292 uint32_t magic_number = GetMagicNumber(); | 307 uint32_t magic_number = GetMagicNumber(); |
293 if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH; | 308 if (magic_number != ComputeMagicNumber(isolate)) return MAGIC_NUMBER_MISMATCH; |
294 uint32_t version_hash = GetHeaderValue(kVersionHashOffset); | 309 uint32_t version_hash = GetHeaderValue(kVersionHashOffset); |
295 uint32_t source_hash = GetHeaderValue(kSourceHashOffset); | 310 uint32_t source_hash = GetHeaderValue(kSourceHashOffset); |
296 uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset); | 311 uint32_t cpu_features = GetHeaderValue(kCpuFeaturesOffset); |
297 uint32_t flags_hash = GetHeaderValue(kFlagHashOffset); | 312 uint32_t flags_hash = GetHeaderValue(kFlagHashOffset); |
298 uint32_t c1 = GetHeaderValue(kChecksum1Offset); | 313 uint32_t c1 = GetHeaderValue(kChecksum1Offset); |
299 uint32_t c2 = GetHeaderValue(kChecksum2Offset); | 314 uint32_t c2 = GetHeaderValue(kChecksum2Offset); |
300 if (version_hash != Version::Hash()) return VERSION_MISMATCH; | 315 if (version_hash != Version::Hash()) return VERSION_MISMATCH; |
301 if (source_hash != SourceHash(source)) return SOURCE_MISMATCH; | 316 if (source_hash != expected_source_hash) return SOURCE_MISMATCH; |
302 if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) { | 317 if (cpu_features != static_cast<uint32_t>(CpuFeatures::SupportedFeatures())) { |
303 return CPU_FEATURES_MISMATCH; | 318 return CPU_FEATURES_MISMATCH; |
304 } | 319 } |
305 if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH; | 320 if (flags_hash != FlagList::Hash()) return FLAGS_MISMATCH; |
306 if (!Checksum(Payload()).Check(c1, c2)) return CHECKSUM_MISMATCH; | 321 if (!Checksum(Payload()).Check(c1, c2)) return CHECKSUM_MISMATCH; |
307 return CHECK_SUCCESS; | 322 return CHECK_SUCCESS; |
308 } | 323 } |
309 | 324 |
310 uint32_t SerializedCodeData::SourceHash(String* source) const { | 325 uint32_t SerializedCodeData::SourceHash(Handle<String> source) { |
311 return source->length(); | 326 return source->length(); |
312 } | 327 } |
313 | 328 |
314 // Return ScriptData object and relinquish ownership over it to the caller. | 329 // Return ScriptData object and relinquish ownership over it to the caller. |
315 ScriptData* SerializedCodeData::GetScriptData() { | 330 ScriptData* SerializedCodeData::GetScriptData() { |
316 DCHECK(owns_data_); | 331 DCHECK(owns_data_); |
317 ScriptData* result = new ScriptData(data_, size_); | 332 ScriptData* result = new ScriptData(data_, size_); |
318 result->AcquireDataOwnership(); | 333 result->AcquireDataOwnership(); |
319 owns_data_ = false; | 334 owns_data_ = false; |
320 data_ = NULL; | 335 data_ = NULL; |
(...skipping 22 matching lines...) Expand all Loading... | |
343 Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const { | 358 Vector<const uint32_t> SerializedCodeData::CodeStubKeys() const { |
344 int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size; | 359 int reservations_size = GetHeaderValue(kNumReservationsOffset) * kInt32Size; |
345 const byte* start = data_ + kHeaderSize + reservations_size; | 360 const byte* start = data_ + kHeaderSize + reservations_size; |
346 return Vector<const uint32_t>(reinterpret_cast<const uint32_t*>(start), | 361 return Vector<const uint32_t>(reinterpret_cast<const uint32_t*>(start), |
347 GetHeaderValue(kNumCodeStubKeysOffset)); | 362 GetHeaderValue(kNumCodeStubKeysOffset)); |
348 } | 363 } |
349 | 364 |
350 SerializedCodeData::SerializedCodeData(ScriptData* data) | 365 SerializedCodeData::SerializedCodeData(ScriptData* data) |
351 : SerializedData(const_cast<byte*>(data->data()), data->length()) {} | 366 : SerializedData(const_cast<byte*>(data->data()), data->length()) {} |
352 | 367 |
353 SerializedCodeData* SerializedCodeData::FromCachedData(Isolate* isolate, | 368 const SerializedCodeData SerializedCodeData::FromCachedData( |
354 ScriptData* cached_data, | 369 Isolate* isolate, ScriptData* cached_data, uint32_t expected_source_hash, |
355 String* source) { | 370 SanityCheckResult* rejection_result) { |
356 DisallowHeapAllocation no_gc; | 371 DisallowHeapAllocation no_gc; |
357 SerializedCodeData* scd = new SerializedCodeData(cached_data); | 372 SerializedCodeData scd(cached_data); |
358 SanityCheckResult r = scd->SanityCheck(isolate, source); | 373 *rejection_result = scd.SanityCheck(isolate, expected_source_hash); |
359 if (r == CHECK_SUCCESS) return scd; | 374 if (*rejection_result != CHECK_SUCCESS) { |
360 cached_data->Reject(); | 375 cached_data->Reject(); |
361 source->GetIsolate()->counters()->code_cache_reject_reason()->AddSample(r); | 376 return SerializedCodeData(nullptr, 0); |
362 delete scd; | 377 } |
363 return NULL; | 378 return scd; |
364 } | 379 } |
365 | 380 |
366 } // namespace internal | 381 } // namespace internal |
367 } // namespace v8 | 382 } // namespace v8 |
OLD | NEW |