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/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 | 22 |
22 template <typename T> | 23 template <typename T> |
23 static size_t BytesNeededForVarint(T value) { | 24 static size_t BytesNeededForVarint(T value) { |
24 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, | 25 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, |
25 "Only unsigned integer types can be written as varints."); | 26 "Only unsigned integer types can be written as varints."); |
(...skipping 977 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1003 ->NewRawTwoByteString(byte_length / sizeof(uc16)) | 1004 ->NewRawTwoByteString(byte_length / sizeof(uc16)) |
1004 .ToHandle(&string)) | 1005 .ToHandle(&string)) |
1005 return MaybeHandle<String>(); | 1006 return MaybeHandle<String>(); |
1006 | 1007 |
1007 // Copy the bytes directly into the new string. | 1008 // Copy the bytes directly into the new string. |
1008 // Warning: this uses host endianness. | 1009 // Warning: this uses host endianness. |
1009 memcpy(string->GetChars(), bytes.begin(), bytes.length()); | 1010 memcpy(string->GetChars(), bytes.begin(), bytes.length()); |
1010 return string; | 1011 return string; |
1011 } | 1012 } |
1012 | 1013 |
| 1014 bool ValueDeserializer::ReadExpectedString(Handle<String> expected) { |
| 1015 // In the case of failure, the position in the stream is reset. |
| 1016 const uint8_t* original_position = position_; |
| 1017 |
| 1018 SerializationTag tag; |
| 1019 uint32_t byte_length; |
| 1020 Vector<const uint8_t> bytes; |
| 1021 if (!ReadTag().To(&tag) || !ReadVarint<uint32_t>().To(&byte_length) || |
| 1022 byte_length > |
| 1023 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) || |
| 1024 !ReadRawBytes(byte_length).To(&bytes)) { |
| 1025 position_ = original_position; |
| 1026 return false; |
| 1027 } |
| 1028 |
| 1029 expected = String::Flatten(expected); |
| 1030 DisallowHeapAllocation no_gc; |
| 1031 String::FlatContent flat = expected->GetFlatContent(); |
| 1032 |
| 1033 // If the bytes are verbatim what is in the flattened string, then the string |
| 1034 // is successfully consumed. |
| 1035 if (tag == SerializationTag::kUtf8String && flat.IsOneByte()) { |
| 1036 Vector<const uint8_t> chars = flat.ToOneByteVector(); |
| 1037 if (byte_length == chars.length() && |
| 1038 String::IsAscii(chars.begin(), chars.length()) && |
| 1039 memcmp(bytes.begin(), chars.begin(), byte_length) == 0) { |
| 1040 return true; |
| 1041 } |
| 1042 } else if (tag == SerializationTag::kTwoByteString && flat.IsTwoByte()) { |
| 1043 Vector<const uc16> chars = flat.ToUC16Vector(); |
| 1044 if (byte_length == static_cast<unsigned>(chars.length()) * sizeof(uc16) && |
| 1045 memcmp(bytes.begin(), chars.begin(), byte_length) == 0) { |
| 1046 return true; |
| 1047 } |
| 1048 } |
| 1049 |
| 1050 position_ = original_position; |
| 1051 return false; |
| 1052 } |
| 1053 |
1013 MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() { | 1054 MaybeHandle<JSObject> ValueDeserializer::ReadJSObject() { |
1014 // If we are at the end of the stack, abort. This function may recurse. | 1055 // If we are at the end of the stack, abort. This function may recurse. |
1015 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); | 1056 STACK_CHECK(isolate_, MaybeHandle<JSObject>()); |
1016 | 1057 |
1017 uint32_t id = next_id_++; | 1058 uint32_t id = next_id_++; |
1018 HandleScope scope(isolate_); | 1059 HandleScope scope(isolate_); |
1019 Handle<JSObject> object = | 1060 Handle<JSObject> object = |
1020 isolate_->factory()->NewJSObject(isolate_->object_function()); | 1061 isolate_->factory()->NewJSObject(isolate_->object_function()); |
1021 AddObjectWithID(id, object); | 1062 AddObjectWithID(id, object); |
1022 | 1063 |
1023 uint32_t num_properties; | 1064 uint32_t num_properties; |
1024 uint32_t expected_num_properties; | 1065 uint32_t expected_num_properties; |
1025 if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject) | 1066 if (!ReadJSObjectProperties(object, SerializationTag::kEndJSObject, true) |
1026 .To(&num_properties) || | 1067 .To(&num_properties) || |
1027 !ReadVarint<uint32_t>().To(&expected_num_properties) || | 1068 !ReadVarint<uint32_t>().To(&expected_num_properties) || |
1028 num_properties != expected_num_properties) { | 1069 num_properties != expected_num_properties) { |
1029 return MaybeHandle<JSObject>(); | 1070 return MaybeHandle<JSObject>(); |
1030 } | 1071 } |
1031 | 1072 |
1032 DCHECK(HasObjectWithID(id)); | 1073 DCHECK(HasObjectWithID(id)); |
1033 return scope.CloseAndEscape(object); | 1074 return scope.CloseAndEscape(object); |
1034 } | 1075 } |
1035 | 1076 |
1036 MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() { | 1077 MaybeHandle<JSArray> ValueDeserializer::ReadSparseJSArray() { |
1037 // If we are at the end of the stack, abort. This function may recurse. | 1078 // If we are at the end of the stack, abort. This function may recurse. |
1038 STACK_CHECK(isolate_, MaybeHandle<JSArray>()); | 1079 STACK_CHECK(isolate_, MaybeHandle<JSArray>()); |
1039 | 1080 |
1040 uint32_t length; | 1081 uint32_t length; |
1041 if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>(); | 1082 if (!ReadVarint<uint32_t>().To(&length)) return MaybeHandle<JSArray>(); |
1042 | 1083 |
1043 uint32_t id = next_id_++; | 1084 uint32_t id = next_id_++; |
1044 HandleScope scope(isolate_); | 1085 HandleScope scope(isolate_); |
1045 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); | 1086 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); |
1046 JSArray::SetLength(array, length); | 1087 JSArray::SetLength(array, length); |
1047 AddObjectWithID(id, array); | 1088 AddObjectWithID(id, array); |
1048 | 1089 |
1049 uint32_t num_properties; | 1090 uint32_t num_properties; |
1050 uint32_t expected_num_properties; | 1091 uint32_t expected_num_properties; |
1051 uint32_t expected_length; | 1092 uint32_t expected_length; |
1052 if (!ReadJSObjectProperties(array, SerializationTag::kEndSparseJSArray) | 1093 if (!ReadJSObjectProperties(array, SerializationTag::kEndSparseJSArray, false) |
1053 .To(&num_properties) || | 1094 .To(&num_properties) || |
1054 !ReadVarint<uint32_t>().To(&expected_num_properties) || | 1095 !ReadVarint<uint32_t>().To(&expected_num_properties) || |
1055 !ReadVarint<uint32_t>().To(&expected_length) || | 1096 !ReadVarint<uint32_t>().To(&expected_length) || |
1056 num_properties != expected_num_properties || length != expected_length) { | 1097 num_properties != expected_num_properties || length != expected_length) { |
1057 return MaybeHandle<JSArray>(); | 1098 return MaybeHandle<JSArray>(); |
1058 } | 1099 } |
1059 | 1100 |
1060 DCHECK(HasObjectWithID(id)); | 1101 DCHECK(HasObjectWithID(id)); |
1061 return scope.CloseAndEscape(array); | 1102 return scope.CloseAndEscape(array); |
1062 } | 1103 } |
(...skipping 16 matching lines...) Expand all Loading... |
1079 Handle<Object> element; | 1120 Handle<Object> element; |
1080 if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>(); | 1121 if (!ReadObject().ToHandle(&element)) return MaybeHandle<JSArray>(); |
1081 // TODO(jbroman): Distinguish between undefined and a hole. | 1122 // TODO(jbroman): Distinguish between undefined and a hole. |
1082 if (element->IsUndefined(isolate_)) continue; | 1123 if (element->IsUndefined(isolate_)) continue; |
1083 elements->set(i, *element); | 1124 elements->set(i, *element); |
1084 } | 1125 } |
1085 | 1126 |
1086 uint32_t num_properties; | 1127 uint32_t num_properties; |
1087 uint32_t expected_num_properties; | 1128 uint32_t expected_num_properties; |
1088 uint32_t expected_length; | 1129 uint32_t expected_length; |
1089 if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray) | 1130 if (!ReadJSObjectProperties(array, SerializationTag::kEndDenseJSArray, false) |
1090 .To(&num_properties) || | 1131 .To(&num_properties) || |
1091 !ReadVarint<uint32_t>().To(&expected_num_properties) || | 1132 !ReadVarint<uint32_t>().To(&expected_num_properties) || |
1092 !ReadVarint<uint32_t>().To(&expected_length) || | 1133 !ReadVarint<uint32_t>().To(&expected_length) || |
1093 num_properties != expected_num_properties || length != expected_length) { | 1134 num_properties != expected_num_properties || length != expected_length) { |
1094 return MaybeHandle<JSArray>(); | 1135 return MaybeHandle<JSArray>(); |
1095 } | 1136 } |
1096 | 1137 |
1097 DCHECK(HasObjectWithID(id)); | 1138 DCHECK(HasObjectWithID(id)); |
1098 return scope.CloseAndEscape(array); | 1139 return scope.CloseAndEscape(array); |
1099 } | 1140 } |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1309 } | 1350 } |
1310 if (byte_offset % element_size != 0 || byte_length % element_size != 0) { | 1351 if (byte_offset % element_size != 0 || byte_length % element_size != 0) { |
1311 return MaybeHandle<JSArrayBufferView>(); | 1352 return MaybeHandle<JSArrayBufferView>(); |
1312 } | 1353 } |
1313 Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray( | 1354 Handle<JSTypedArray> typed_array = isolate_->factory()->NewJSTypedArray( |
1314 external_array_type, buffer, byte_offset, byte_length / element_size); | 1355 external_array_type, buffer, byte_offset, byte_length / element_size); |
1315 AddObjectWithID(id, typed_array); | 1356 AddObjectWithID(id, typed_array); |
1316 return typed_array; | 1357 return typed_array; |
1317 } | 1358 } |
1318 | 1359 |
| 1360 // Copies a vector of property values into an object, given the map that should |
| 1361 // be used. |
| 1362 static void CommitProperties(Handle<JSObject> object, Handle<Map> map, |
| 1363 const std::vector<Handle<Object>>& properties) { |
| 1364 JSObject::AllocateStorageForMap(object, map); |
| 1365 DCHECK(!object->map()->is_dictionary_map()); |
| 1366 |
| 1367 DisallowHeapAllocation no_gc; |
| 1368 DescriptorArray* descriptors = object->map()->instance_descriptors(); |
| 1369 for (unsigned i = 0; i < properties.size(); i++) { |
| 1370 object->WriteToField(i, descriptors->GetDetails(i), *properties[i]); |
| 1371 } |
| 1372 } |
| 1373 |
1319 Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties( | 1374 Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties( |
1320 Handle<JSObject> object, SerializationTag end_tag) { | 1375 Handle<JSObject> object, SerializationTag end_tag, |
1321 for (uint32_t num_properties = 0;; num_properties++) { | 1376 bool can_use_transitions) { |
| 1377 uint32_t num_properties = 0; |
| 1378 |
| 1379 // Fast path (following map transitions). |
| 1380 if (can_use_transitions) { |
| 1381 bool transitioning = true; |
| 1382 Handle<Map> map(object->map(), isolate_); |
| 1383 DCHECK(!map->is_dictionary_map()); |
| 1384 DCHECK(map->instance_descriptors()->IsEmpty()); |
| 1385 std::vector<Handle<Object>> properties; |
| 1386 properties.reserve(8); |
| 1387 |
| 1388 while (transitioning) { |
| 1389 // If there are no more properties, finish. |
| 1390 SerializationTag tag; |
| 1391 if (!PeekTag().To(&tag)) return Nothing<uint32_t>(); |
| 1392 if (tag == end_tag) { |
| 1393 ConsumeTag(end_tag); |
| 1394 CommitProperties(object, map, properties); |
| 1395 CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max()); |
| 1396 return Just(static_cast<uint32_t>(properties.size())); |
| 1397 } |
| 1398 |
| 1399 // Determine the key to be used and the target map to transition to, if |
| 1400 // possible. Transitioning may abort if the key is not a string, or if no |
| 1401 // transition was found. |
| 1402 Handle<Object> key; |
| 1403 Handle<Map> target; |
| 1404 Handle<String> expected_key = TransitionArray::ExpectedTransitionKey(map); |
| 1405 if (!expected_key.is_null() && ReadExpectedString(expected_key)) { |
| 1406 key = expected_key; |
| 1407 target = TransitionArray::ExpectedTransitionTarget(map); |
| 1408 } else { |
| 1409 if (!ReadObject().ToHandle(&key)) return Nothing<uint32_t>(); |
| 1410 if (key->IsString()) { |
| 1411 key = |
| 1412 isolate_->factory()->InternalizeString(Handle<String>::cast(key)); |
| 1413 target = TransitionArray::FindTransitionToField( |
| 1414 map, Handle<String>::cast(key)); |
| 1415 transitioning = !target.is_null(); |
| 1416 } else { |
| 1417 transitioning = false; |
| 1418 } |
| 1419 } |
| 1420 |
| 1421 // Read the value that corresponds to it. |
| 1422 Handle<Object> value; |
| 1423 if (!ReadObject().ToHandle(&value)) return Nothing<uint32_t>(); |
| 1424 |
| 1425 // If still transitioning and the value fits the field representation |
| 1426 // (though generalization may be required), store the property value so |
| 1427 // that we can copy them all at once. Otherwise, stop transitioning. |
| 1428 if (transitioning) { |
| 1429 int descriptor = static_cast<int>(properties.size()); |
| 1430 PropertyDetails details = |
| 1431 target->instance_descriptors()->GetDetails(descriptor); |
| 1432 Representation expected_representation = details.representation(); |
| 1433 if (value->FitsRepresentation(expected_representation)) { |
| 1434 if (expected_representation.IsHeapObject() && |
| 1435 !target->instance_descriptors() |
| 1436 ->GetFieldType(descriptor) |
| 1437 ->NowContains(value)) { |
| 1438 Handle<FieldType> value_type = |
| 1439 value->OptimalType(isolate_, expected_representation); |
| 1440 Map::GeneralizeFieldType(target, descriptor, |
| 1441 expected_representation, value_type); |
| 1442 } |
| 1443 DCHECK(target->instance_descriptors() |
| 1444 ->GetFieldType(descriptor) |
| 1445 ->NowContains(value)); |
| 1446 properties.push_back(value); |
| 1447 map = target; |
| 1448 continue; |
| 1449 } else { |
| 1450 transitioning = false; |
| 1451 } |
| 1452 } |
| 1453 |
| 1454 // Fell out of transitioning fast path. Commit the properties gathered so |
| 1455 // far, and then start setting properties slowly instead. |
| 1456 DCHECK(!transitioning); |
| 1457 CHECK_LT(properties.size(), std::numeric_limits<uint32_t>::max()); |
| 1458 CommitProperties(object, map, properties); |
| 1459 num_properties = static_cast<uint32_t>(properties.size()); |
| 1460 |
| 1461 bool success; |
| 1462 LookupIterator it = LookupIterator::PropertyOrElement( |
| 1463 isolate_, object, key, &success, LookupIterator::OWN); |
| 1464 if (!success || |
| 1465 JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE) |
| 1466 .is_null()) { |
| 1467 return Nothing<uint32_t>(); |
| 1468 } |
| 1469 num_properties++; |
| 1470 } |
| 1471 |
| 1472 // At this point, transitioning should be done, but at least one property |
| 1473 // should have been written (in the zero-property case, there is an early |
| 1474 // return). |
| 1475 DCHECK(!transitioning); |
| 1476 DCHECK_GE(num_properties, 1u); |
| 1477 } |
| 1478 |
| 1479 // Slow path. |
| 1480 for (;; num_properties++) { |
1322 SerializationTag tag; | 1481 SerializationTag tag; |
1323 if (!PeekTag().To(&tag)) return Nothing<uint32_t>(); | 1482 if (!PeekTag().To(&tag)) return Nothing<uint32_t>(); |
1324 if (tag == end_tag) { | 1483 if (tag == end_tag) { |
1325 ConsumeTag(end_tag); | 1484 ConsumeTag(end_tag); |
1326 return Just(num_properties); | 1485 return Just(num_properties); |
1327 } | 1486 } |
1328 | 1487 |
1329 Handle<Object> key; | 1488 Handle<Object> key; |
1330 if (!ReadObject().ToHandle(&key)) return Nothing<uint32_t>(); | 1489 if (!ReadObject().ToHandle(&key)) return Nothing<uint32_t>(); |
1331 Handle<Object> value; | 1490 Handle<Object> value; |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1479 if (stack.size() != 1) { | 1638 if (stack.size() != 1) { |
1480 isolate_->Throw(*isolate_->factory()->NewError( | 1639 isolate_->Throw(*isolate_->factory()->NewError( |
1481 MessageTemplate::kDataCloneDeserializationError)); | 1640 MessageTemplate::kDataCloneDeserializationError)); |
1482 return MaybeHandle<Object>(); | 1641 return MaybeHandle<Object>(); |
1483 } | 1642 } |
1484 return scope.CloseAndEscape(stack[0]); | 1643 return scope.CloseAndEscape(stack[0]); |
1485 } | 1644 } |
1486 | 1645 |
1487 } // namespace internal | 1646 } // namespace internal |
1488 } // namespace v8 | 1647 } // namespace v8 |
OLD | NEW |