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/value-serializer.h" | 5 #include "src/value-serializer.h" |
| 6 | 6 |
| 7 #include <type_traits> | 7 #include <type_traits> |
| 8 | 8 |
| 9 #include "src/base/logging.h" | 9 #include "src/base/logging.h" |
| 10 #include "src/conversions.h" | 10 #include "src/conversions.h" |
| 11 #include "src/factory.h" | 11 #include "src/factory.h" |
| 12 #include "src/flags.h" | 12 #include "src/flags.h" |
| 13 #include "src/handles-inl.h" | 13 #include "src/handles-inl.h" |
| 14 #include "src/isolate.h" | 14 #include "src/isolate.h" |
| 15 #include "src/objects-inl.h" | 15 #include "src/objects-inl.h" |
| 16 #include "src/objects.h" | 16 #include "src/objects.h" |
| 17 #include "src/snapshot/code-serializer.h" | 17 #include "src/snapshot/code-serializer.h" |
| 18 #include "src/transitions.h" | 18 #include "src/transitions.h" |
| 19 #include "src/wasm/wasm-module.h" | 19 #include "src/wasm/wasm-module.h" |
| 20 #include "src/wasm/wasm-objects.h" | 20 #include "src/wasm/wasm-objects.h" |
| 21 #include "src/wasm/wasm-result.h" | 21 #include "src/wasm/wasm-result.h" |
| 22 | 22 |
| 23 namespace v8 { | 23 namespace v8 { |
| 24 namespace internal { | 24 namespace internal { |
| 25 | 25 |
| 26 // Version 9: (imported from Blink) | 26 // Version 9: (imported from Blink) |
| 27 // Version 10: one-byte (Latin-1) strings | 27 // Version 10: one-byte (Latin-1) strings |
| 28 static const uint32_t kLatestVersion = 10; | 28 // Version 11: properly separate undefined from the hole in arrays |
| 29 static const uint32_t kLatestVersion = 11; | |
| 29 | 30 |
| 30 static const int kPretenureThreshold = 100 * KB; | 31 static const int kPretenureThreshold = 100 * KB; |
| 31 | 32 |
| 32 template <typename T> | 33 template <typename T> |
| 33 static size_t BytesNeededForVarint(T value) { | 34 static size_t BytesNeededForVarint(T value) { |
| 34 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, | 35 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, |
| 35 "Only unsigned integer types can be written as varints."); | 36 "Only unsigned integer types can be written as varints."); |
| 36 size_t result = 0; | 37 size_t result = 0; |
| 37 do { | 38 do { |
| 38 result++; | 39 result++; |
| 39 value >>= 7; | 40 value >>= 7; |
| 40 } while (value); | 41 } while (value); |
| 41 return result; | 42 return result; |
| 42 } | 43 } |
| 43 | 44 |
| 44 enum class SerializationTag : uint8_t { | 45 enum class SerializationTag : uint8_t { |
| 45 // version:uint32_t (if at beginning of data, sets version > 0) | 46 // version:uint32_t (if at beginning of data, sets version > 0) |
| 46 kVersion = 0xFF, | 47 kVersion = 0xFF, |
| 47 // ignore | 48 // ignore |
| 48 kPadding = '\0', | 49 kPadding = '\0', |
| 49 // refTableSize:uint32_t (previously used for sanity checks; safe to ignore) | 50 // refTableSize:uint32_t (previously used for sanity checks; safe to ignore) |
| 50 kVerifyObjectCount = '?', | 51 kVerifyObjectCount = '?', |
| 51 // Oddballs (no data). | 52 // Oddballs (no data). |
| 53 kTheHole = '-', | |
| 52 kUndefined = '_', | 54 kUndefined = '_', |
| 53 kNull = '0', | 55 kNull = '0', |
| 54 kTrue = 'T', | 56 kTrue = 'T', |
| 55 kFalse = 'F', | 57 kFalse = 'F', |
| 56 // Number represented as 32-bit integer, ZigZag-encoded | 58 // Number represented as 32-bit integer, ZigZag-encoded |
| 57 // (like sint32 in protobuf) | 59 // (like sint32 in protobuf) |
| 58 kInt32 = 'I', | 60 kInt32 = 'I', |
| 59 // Number represented as 32-bit unsigned integer, varint-encoded | 61 // Number represented as 32-bit unsigned integer, varint-encoded |
| 60 // (like uint32 in protobuf) | 62 // (like uint32 in protobuf) |
| 61 kUint32 = 'U', | 63 kUint32 = 'U', |
| (...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 532 // serialization based on elements kind. A more principled heuristic could | 534 // serialization based on elements kind. A more principled heuristic could |
| 533 // count the elements, but would need to take care to note which indices | 535 // count the elements, but would need to take care to note which indices |
| 534 // existed (as only indices which were enumerable own properties at this point | 536 // existed (as only indices which were enumerable own properties at this point |
| 535 // should be serialized). | 537 // should be serialized). |
| 536 const bool should_serialize_densely = | 538 const bool should_serialize_densely = |
| 537 array->HasFastElements() && !array->HasFastHoleyElements(); | 539 array->HasFastElements() && !array->HasFastHoleyElements(); |
| 538 | 540 |
| 539 if (should_serialize_densely) { | 541 if (should_serialize_densely) { |
| 540 DCHECK_LE(length, static_cast<uint32_t>(FixedArray::kMaxLength)); | 542 DCHECK_LE(length, static_cast<uint32_t>(FixedArray::kMaxLength)); |
| 541 | 543 |
| 542 // TODO(jbroman): Distinguish between undefined and a hole (this can happen | 544 // TODO(jbroman): Distinguish between undefined and a hole (this can happen |
|
Jakob Kummerow
2017/01/30 03:11:38
nit: you can drop this :-)
jbroman
2017/01/30 18:08:29
Done!
| |
| 543 // if serializing one of the elements deletes another). This requires wire | 545 // if serializing one of the elements deletes another). This requires wire |
| 544 // format changes. | 546 // format changes. |
| 545 WriteTag(SerializationTag::kBeginDenseJSArray); | 547 WriteTag(SerializationTag::kBeginDenseJSArray); |
| 546 WriteVarint<uint32_t>(length); | 548 WriteVarint<uint32_t>(length); |
| 547 uint32_t i = 0; | 549 uint32_t i = 0; |
| 548 | 550 |
| 549 // Fast paths. Note that FAST_ELEMENTS in particular can bail due to the | 551 // Fast paths. Note that FAST_ELEMENTS in particular can bail due to the |
| 550 // structure of the elements changing. | 552 // structure of the elements changing. |
| 551 switch (array->GetElementsKind()) { | 553 switch (array->GetElementsKind()) { |
| 552 case FAST_SMI_ELEMENTS: { | 554 case FAST_SMI_ELEMENTS: { |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 582 break; | 584 break; |
| 583 } | 585 } |
| 584 | 586 |
| 585 // If there are elements remaining, serialize them slowly. | 587 // If there are elements remaining, serialize them slowly. |
| 586 for (; i < length; i++) { | 588 for (; i < length; i++) { |
| 587 // Serializing the array's elements can have arbitrary side effects, so we | 589 // Serializing the array's elements can have arbitrary side effects, so we |
| 588 // cannot rely on still having fast elements, even if it did to begin | 590 // cannot rely on still having fast elements, even if it did to begin |
| 589 // with. | 591 // with. |
| 590 Handle<Object> element; | 592 Handle<Object> element; |
| 591 LookupIterator it(isolate_, array, i, array, LookupIterator::OWN); | 593 LookupIterator it(isolate_, array, i, array, LookupIterator::OWN); |
| 594 if (!it.IsFound()) { | |
| 595 // This can happen in the case where an array that was originally dense | |
| 596 // became sparse during serialization. It's too late to switch to the | |
| 597 // sparse format, but we can mark the elements as absent. | |
| 598 WriteTag(SerializationTag::kTheHole); | |
| 599 continue; | |
| 600 } | |
| 592 if (!Object::GetProperty(&it).ToHandle(&element) || | 601 if (!Object::GetProperty(&it).ToHandle(&element) || |
| 593 !WriteObject(element).FromMaybe(false)) { | 602 !WriteObject(element).FromMaybe(false)) { |
| 594 return Nothing<bool>(); | 603 return Nothing<bool>(); |
| 595 } | 604 } |
| 596 } | 605 } |
| 597 | 606 |
| 598 KeyAccumulator accumulator(isolate_, KeyCollectionMode::kOwnOnly, | 607 KeyAccumulator accumulator(isolate_, KeyCollectionMode::kOwnOnly, |
| 599 ENUMERABLE_STRINGS); | 608 ENUMERABLE_STRINGS); |
| 600 if (!accumulator.CollectOwnPropertyNames(array, array).FromMaybe(false)) { | 609 if (!accumulator.CollectOwnPropertyNames(array, array).FromMaybe(false)) { |
| 601 return Nothing<bool>(); | 610 return Nothing<bool>(); |
| (...skipping 711 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1313 | 1322 |
| 1314 uint32_t id = next_id_++; | 1323 uint32_t id = next_id_++; |
| 1315 HandleScope scope(isolate_); | 1324 HandleScope scope(isolate_); |
| 1316 Handle<JSArray> array = isolate_->factory()->NewJSArray( | 1325 Handle<JSArray> array = isolate_->factory()->NewJSArray( |
| 1317 FAST_HOLEY_ELEMENTS, length, length, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE, | 1326 FAST_HOLEY_ELEMENTS, length, length, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE, |
| 1318 pretenure_); | 1327 pretenure_); |
| 1319 AddObjectWithID(id, array); | 1328 AddObjectWithID(id, array); |
| 1320 | 1329 |
| 1321 Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate_); | 1330 Handle<FixedArray> elements(FixedArray::cast(array->elements()), isolate_); |
| 1322 for (uint32_t i = 0; i < length; i++) { | 1331 for (uint32_t i = 0; i < length; i++) { |
| 1332 SerializationTag tag; | |
| 1333 if (PeekTag().To(&tag) && tag == SerializationTag::kTheHole) { | |
| 1334 ConsumeTag(SerializationTag::kTheHole); | |
| 1335 continue; | |
| 1336 } | |
| 1337 | |
| 1323 Handle<Object> element; | 1338 Handle<Object> element; |
| 1324 if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>(); | 1339 if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>(); |
| 1325 // TODO(jbroman): Distinguish between undefined and a hole. | 1340 |
| 1326 if (element->IsUndefined(isolate_)) continue; | 1341 // Serialization versions less than 11 encode the hole the same as |
| 1342 // undefined. For consistency with previous behavior, store these as the | |
| 1343 // hole. Past version 11, undefined means undefined. | |
| 1344 if (version_ < 11 && element->IsUndefined(isolate_)) continue; | |
| 1345 | |
| 1327 elements->set(i, *element); | 1346 elements->set(i, *element); |
| 1328 } | 1347 } |
| 1329 | 1348 |
| 1330 uint32_t num_properties; | 1349 uint32_t num_properties; |
| 1331 uint32_t expected_num_properties; | 1350 uint32_t expected_num_properties; |
| 1332 uint32_t expected_length; | 1351 uint32_t expected_length; |
| 1333 if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray, false) | 1352 if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray, false) |
| 1334 .To(&num_properties) || | 1353 .To(&num_properties) || |
| 1335 !ReadVarint<uint32_t>().To(&expected_num_properties) || | 1354 !ReadVarint<uint32_t>().To(&expected_num_properties) || |
| 1336 !ReadVarint<uint32_t>().To(&expected_length) || | 1355 !ReadVarint<uint32_t>().To(&expected_length) || |
| (...skipping 582 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1919 if (stack.size() != 1) { | 1938 if (stack.size() != 1) { |
| 1920 isolate_->Throw(*isolate_->factory()->NewError( | 1939 isolate_->Throw(*isolate_->factory()->NewError( |
| 1921 MessageTemplate::kDataCloneDeserializationError)); | 1940 MessageTemplate::kDataCloneDeserializationError)); |
| 1922 return MaybeHandle<Object>(); | 1941 return MaybeHandle<Object>(); |
| 1923 } | 1942 } |
| 1924 return scope.CloseAndEscape(stack[0]); | 1943 return scope.CloseAndEscape(stack[0]); |
| 1925 } | 1944 } |
| 1926 | 1945 |
| 1927 } // namespace internal | 1946 } // namespace internal |
| 1928 } // namespace v8 | 1947 } // namespace v8 |
| OLD | NEW |