Chromium Code Reviews| 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 |