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 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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |