Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(148)

Side by Side Diff: src/value-serializer.cc

Issue 2334353002: Follow object map transitions when deserializing object properties. (Closed)
Patch Set: update unit tests per cbruni Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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/handles-inl.h" 12 #include "src/handles-inl.h"
13 #include "src/isolate.h" 13 #include "src/isolate.h"
14 #include "src/objects-inl.h" 14 #include "src/objects-inl.h"
15 #include "src/objects.h" 15 #include "src/objects.h"
16 #include "src/transitions.h"
16 17
17 namespace v8 { 18 namespace v8 {
18 namespace internal { 19 namespace internal {
19 20
20 static const uint32_t kLatestVersion = 9; 21 static const uint32_t kLatestVersion = 9;
21 static const int kPretenureThreshold = 100 * KB; 22 static const int kPretenureThreshold = 100 * KB;
22 23
23 template <typename T> 24 template <typename T>
24 static size_t BytesNeededForVarint(T value) { 25 static size_t BytesNeededForVarint(T value) {
25 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, 26 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
(...skipping 1029 matching lines...) Expand 10 before | Expand all | Expand 10 after
1055 ->NewRawTwoByteString(byte_length / sizeof(uc16), pretenure_) 1056 ->NewRawTwoByteString(byte_length / sizeof(uc16), pretenure_)
1056 .ToHandle(&string)) 1057 .ToHandle(&string))
1057 return MaybeHandle<String>(); 1058 return MaybeHandle<String>();
1058 1059
1059 // Copy the bytes directly into the new string. 1060 // Copy the bytes directly into the new string.
1060 // Warning: this uses host endianness. 1061 // Warning: this uses host endianness.
1061 memcpy(string->GetChars(), bytes.begin(), bytes.length()); 1062 memcpy(string->GetChars(), bytes.begin(), bytes.length());
1062 return string; 1063 return string;
1063 } 1064 }
1064 1065
1066 bool ValueDeserializer::ReadExpectedString(Handle<String> expected) {
1067 // In the case of failure, the position in the stream is reset.
1068 const uint8_t* original_position = position_;
1069
1070 SerializationTag tag;
1071 uint32_t byte_length;
1072 Vector<const uint8_t> bytes;
1073 if (!ReadTag().To(&tag) || !ReadVarint<uint32_t>().To(&byte_length) ||
1074 byte_length >
1075 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
1076 !ReadRawBytes(byte_length).To(&bytes)) {
1077 position_ = original_position;
1078 return false;
1079 }
1080
1081 expected = String::Flatten(expected);
1082 DisallowHeapAllocation no_gc;
1083 String::FlatContent flat = expected->GetFlatContent();
1084
1085 // If the bytes are verbatim what is in the flattened string, then the string
1086 // is successfully consumed.
1087 if (tag == SerializationTag::kUtf8String && flat.IsOneByte()) {
1088 Vector<const uint8_t> chars = flat.ToOneByteVector();
1089 if (byte_length == chars.length() &&
1090 String::IsAscii(chars.begin(), chars.length()) &&
1091 memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
1092 return true;
1093 }
1094 } else if (tag == SerializationTag::kTwoByteString && flat.IsTwoByte()) {
1095 Vector<const uc16> chars = flat.ToUC16Vector();
1096 if (byte_length == static_cast<unsigned>(chars.length()) * sizeof(uc16) &&
1097 memcmp(bytes.begin(), chars.begin(), byte_length) == 0) {
1098 return true;
1099 }
1100 }
1101
1102 position_ = original_position;
1103 return false;
1104 }
1105
1065 MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() { 1106 MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() {
1066 // If we are at the end of the stack, abort. This function may recurse. 1107 // If we are at the end of the stack, abort. This function may recurse.
1067 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); 1108 STACK_CHECK(isolate_, MaybeHandle<JSObject>());
1068 1109
1069 uint32_t id = next_id_++; 1110 uint32_t id = next_id_++;
1070 HandleScope scope(isolate_); 1111 HandleScope scope(isolate_);
1071 Handle<JSObject> object = 1112 Handle<JSObject> object =
1072 isolate_->factory()->NewJSObject(isolate_->object_function(), pretenure_); 1113 isolate_->factory()->NewJSObject(isolate_->object_function(), pretenure_);
1073 AddObjectWithID(id, object); 1114 AddObjectWithID(id, object);
1074 1115
1075 uint32_t num_properties; 1116 uint32_t num_properties;
1076 uint32_t expected_num_properties; 1117 uint32_t expected_num_properties;
1077 if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject) 1118 if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject, true)
1078 .To(&num_properties) || 1119 .To(&num_properties) ||
1079 !ReadVarint<uint32_t>().To(&expected_num_properties) || 1120 !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1080 num_properties != expected_num_properties) { 1121 num_properties != expected_num_properties) {
1081 return MaybeHandle<JSObject>(); 1122 return MaybeHandle<JSObject>();
1082 } 1123 }
1083 1124
1084 DCHECK(HasObjectWithID(id)); 1125 DCHECK(HasObjectWithID(id));
1085 return scope.CloseAndEscape(object); 1126 return scope.CloseAndEscape(object);
1086 } 1127 }
1087 1128
1088 MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() { 1129 MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() {
1089 // If we are at the end of the stack, abort. This function may recurse. 1130 // If we are at the end of the stack, abort. This function may recurse.
1090 STACK_CHECK(isolate_, MaybeHandle<JSArray>()); 1131 STACK_CHECK(isolate_, MaybeHandle<JSArray>());
1091 1132
1092 uint32_t length; 1133 uint32_t length;
1093 if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>(); 1134 if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>();
1094 1135
1095 uint32_t id = next_id_++; 1136 uint32_t id = next_id_++;
1096 HandleScope scope(isolate_); 1137 HandleScope scope(isolate_);
1097 Handle<JSArray> array = isolate_->factory()->NewJSArray( 1138 Handle<JSArray> array = isolate_->factory()->NewJSArray(
1098 0, TERMINAL_FAST_ELEMENTS_KIND, pretenure_); 1139 0, TERMINAL_FAST_ELEMENTS_KIND, pretenure_);
1099 JSArray::SetLength(array, length); 1140 JSArray::SetLength(array, length);
1100 AddObjectWithID(id, array); 1141 AddObjectWithID(id, array);
1101 1142
1102 uint32_t num_properties; 1143 uint32_t num_properties;
1103 uint32_t expected_num_properties; 1144 uint32_t expected_num_properties;
1104 uint32_t expected_length; 1145 uint32_t expected_length;
1105 if (!ReadJSObjectProperties(array, SerializationTag::kEndSparseJSArray) 1146 if (!ReadJSObjectProperties(array, SerializationTag::kEndSparseJSArray, false)
1106 .To(&num_properties) || 1147 .To(&num_properties) ||
1107 !ReadVarint<uint32_t>().To(&expected_num_properties) || 1148 !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1108 !ReadVarint<uint32_t>().To(&expected_length) || 1149 !ReadVarint<uint32_t>().To(&expected_length) ||
1109 num_properties != expected_num_properties || length != expected_length) { 1150 num_properties != expected_num_properties || length != expected_length) {
1110 return MaybeHandle<JSArray>(); 1151 return MaybeHandle<JSArray>();
1111 } 1152 }
1112 1153
1113 DCHECK(HasObjectWithID(id)); 1154 DCHECK(HasObjectWithID(id));
1114 return scope.CloseAndEscape(array); 1155 return scope.CloseAndEscape(array);
1115 } 1156 }
(...skipping 17 matching lines...) Expand all
1133 Handle<Object> element; 1174 Handle<Object> element;
1134 if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>(); 1175 if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>();
1135 // TODO(jbroman): Distinguish between undefined and a hole. 1176 // TODO(jbroman): Distinguish between undefined and a hole.
1136 if (element->IsUndefined(isolate_)) continue; 1177 if (element->IsUndefined(isolate_)) continue;
1137 elements->set(i, *element); 1178 elements->set(i, *element);
1138 } 1179 }
1139 1180
1140 uint32_t num_properties; 1181 uint32_t num_properties;
1141 uint32_t expected_num_properties; 1182 uint32_t expected_num_properties;
1142 uint32_t expected_length; 1183 uint32_t expected_length;
1143 if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray) 1184 if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray, false)
1144 .To(&num_properties) || 1185 .To(&num_properties) ||
1145 !ReadVarint<uint32_t>().To(&expected_num_properties) || 1186 !ReadVarint<uint32_t>().To(&expected_num_properties) ||
1146 !ReadVarint<uint32_t>().To(&expected_length) || 1187 !ReadVarint<uint32_t>().To(&expected_length) ||
1147 num_properties != expected_num_properties || length != expected_length) { 1188 num_properties != expected_num_properties || length != expected_length) {
1148 return MaybeHandle<JSArray>(); 1189 return MaybeHandle<JSArray>();
1149 } 1190 }
1150 1191
1151 DCHECK(HasObjectWithID(id)); 1192 DCHECK(HasObjectWithID(id));
1152 return scope.CloseAndEscape(array); 1193 return scope.CloseAndEscape(array);
1153 } 1194 }
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
1382 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) { 1423 if (!delegate_->ReadHostObject(v8_isolate).ToLocal(&object)) {
1383 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject); 1424 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate_, JSObject);
1384 return MaybeHandle<JSObject>(); 1425 return MaybeHandle<JSObject>();
1385 } 1426 }
1386 Handle<JSObject> js_object = 1427 Handle<JSObject> js_object =
1387 Handle<JSObject>::cast(Utils::OpenHandle(*object)); 1428 Handle<JSObject>::cast(Utils::OpenHandle(*object));
1388 AddObjectWithID(id, js_object); 1429 AddObjectWithID(id, js_object);
1389 return js_object; 1430 return js_object;
1390 } 1431 }
1391 1432
1433 // Copies a vector of property values into an object, given the map that should
1434 // be used.
1435 static void CommitProperties(Handle<JSObject> object, Handle<Map> map,
1436 const std::vector<Handle<Object>>& properties) {
1437 JSObject::AllocateStorageForMap(object, map);
1438 DCHECK(!object->map()->is_dictionary_map());
1439
1440 DisallowHeapAllocation no_gc;
1441 DescriptorArray* descriptors = object->map()->instance_descriptors();
1442 for (unsigned i = 0; i < properties.size(); i++) {
1443 object->WriteToField(i, descriptors->GetDetails(i), *properties[i]);
1444 }
1445 }
1446
1392 Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties( 1447 Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
1393 Handle<JSObject> object, SerializationTag end_tag) { 1448 Handle<JSObject> object, SerializationTag end_tag,
1394 for (uint32_t num_properties = 0;; num_properties++) { 1449 bool can_use_transitions) {
1450 uint32_t num_properties = 0;
1451
1452 // Fast path (following map transitions).
1453 if (can_use_transitions) {
1454 bool transitioning = true;
1455 Handle<Map> map(object->map(), isolate_);
1456 DCHECK(!map->is_dictionary_map());
1457 DCHECK(map->instance_descriptors()->IsEmpty());
1458 std::vector<Handle<Object>> properties;
1459 properties.reserve(8);
1460
1461 while (transitioning) {
1462 // If there are no more properties, finish.
1463 SerializationTag tag;
1464 if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
1465 if (tag == end_tag) {
1466 ConsumeTag(end_tag);
1467 CommitProperties(object, map, properties);
1468 CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
1469 return Just(static_cast<uint32_t>(properties.size()));
1470 }
1471
1472 // Determine the key to be used and the target map to transition to, if
1473 // possible. Transitioning may abort if the key is not a string, or if no
1474 // transition was found.
1475 Handle<Object> key;
1476 Handle<Map> target;
1477 Handle<String> expected_key = TransitionArray::ExpectedTransitionKey(map);
1478 if (!expected_key.is_null() && ReadExpectedString(expected_key)) {
1479 key = expected_key;
1480 target = TransitionArray::ExpectedTransitionTarget(map);
1481 } else {
1482 if (!ReadObject().ToHandle(&key)) return Nothing<uint32_t>();
1483 if (key->IsString()) {
1484 key =
1485 isolate_->factory()->InternalizeString(Handle<String>::cast(key));
1486 target = TransitionArray::FindTransitionToField(
1487 map, Handle<String>::cast(key));
1488 transitioning = !target.is_null();
1489 } else {
1490 transitioning = false;
1491 }
1492 }
1493
1494 // Read the value that corresponds to it.
1495 Handle<Object> value;
1496 if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>();
1497
1498 // If still transitioning and the value fits the field representation
1499 // (though generalization may be required), store the property value so
1500 // that we can copy them all at once. Otherwise, stop transitioning.
1501 if (transitioning) {
1502 int descriptor = static_cast<int>(properties.size());
1503 PropertyDetails details =
1504 target->instance_descriptors()->GetDetails(descriptor);
1505 Representation expected_representation = details.representation();
1506 if (value->FitsRepresentation(expected_representation)) {
1507 if (expected_representation.IsHeapObject() &&
1508 !target->instance_descriptors()
1509 ->GetFieldType(descriptor)
1510 ->NowContains(value)) {
1511 Handle<FieldType> value_type =
1512 value->OptimalType(isolate_, expected_representation);
1513 Map::GeneralizeFieldType(target, descriptor,
1514 expected_representation, value_type);
1515 }
1516 DCHECK(target->instance_descriptors()
1517 ->GetFieldType(descriptor)
1518 ->NowContains(value));
1519 properties.push_back(value);
1520 map = target;
1521 continue;
1522 } else {
1523 transitioning = false;
1524 }
1525 }
1526
1527 // Fell out of transitioning fast path. Commit the properties gathered so
1528 // far, and then start setting properties slowly instead.
1529 DCHECK(!transitioning);
1530 CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max());
1531 CommitProperties(object, map, properties);
1532 num_properties = static_cast<uint32_t>(properties.size());
1533
1534 bool success;
1535 LookupIterator it = LookupIterator::PropertyOrElement(
1536 isolate_, object, key, &success, LookupIterator::OWN);
1537 if (!success ||
1538 JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE)
1539 .is_null()) {
1540 return Nothing<uint32_t>();
1541 }
1542 num_properties++;
1543 }
1544
1545 // At this point, transitioning should be done, but at least one property
1546 // should have been written (in the zero-property case, there is an early
1547 // return).
1548 DCHECK(!transitioning);
1549 DCHECK_GE(num_properties, 1u);
1550 }
1551
1552 // Slow path.
1553 for (;; num_properties++) {
1395 SerializationTag tag; 1554 SerializationTag tag;
1396 if (!PeekTag().To(&tag)) return Nothing<uint32_t>(); 1555 if (!PeekTag().To(&tag)) return Nothing<uint32_t>();
1397 if (tag == end_tag) { 1556 if (tag == end_tag) {
1398 ConsumeTag(end_tag); 1557 ConsumeTag(end_tag);
1399 return Just(num_properties); 1558 return Just(num_properties);
1400 } 1559 }
1401 1560
1402 Handle<Object> key; 1561 Handle<Object> key;
1403 if (!ReadObject().ToHandle(&key)) return Nothing<uint32_t>(); 1562 if (!ReadObject().ToHandle(&key)) return Nothing<uint32_t>();
1404 Handle<Object> value; 1563 Handle<Object> value;
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after
1553 if (stack.size() != 1) { 1712 if (stack.size() != 1) {
1554 isolate_->Throw(*isolate_->factory()->NewError( 1713 isolate_->Throw(*isolate_->factory()->NewError(
1555 MessageTemplate::kDataCloneDeserializationError)); 1714 MessageTemplate::kDataCloneDeserializationError));
1556 return MaybeHandle<Object>(); 1715 return MaybeHandle<Object>();
1557 } 1716 }
1558 return scope.CloseAndEscape(stack[0]); 1717 return scope.CloseAndEscape(stack[0]);
1559 } 1718 }
1560 1719
1561 } // namespace internal 1720 } // namespace internal
1562 } // namespace v8 1721 } // namespace v8
OLDNEW
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698