| 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" |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 64 // Number represented as 32-bit unsigned integer, varint-encoded | 64 // Number represented as 32-bit unsigned integer, varint-encoded |
| 65 // (like uint32 in protobuf) | 65 // (like uint32 in protobuf) |
| 66 kUint32 = 'U', | 66 kUint32 = 'U', |
| 67 // Number represented as a 64-bit double. | 67 // Number represented as a 64-bit double. |
| 68 // Host byte order is used (N.B. this makes the format non-portable). | 68 // Host byte order is used (N.B. this makes the format non-portable). |
| 69 kDouble = 'N', | 69 kDouble = 'N', |
| 70 // byteLength:uint32_t, then raw data | 70 // byteLength:uint32_t, then raw data |
| 71 kUtf8String = 'S', | 71 kUtf8String = 'S', |
| 72 kOneByteString = '"', | 72 kOneByteString = '"', |
| 73 kTwoByteString = 'c', | 73 kTwoByteString = 'c', |
| 74 // ID:uint32_t. Only used if the client requests it. |
| 75 kLongString = '>', |
| 74 // Reference to a serialized object. objectID:uint32_t | 76 // Reference to a serialized object. objectID:uint32_t |
| 75 kObjectReference = '^', | 77 kObjectReference = '^', |
| 76 // Beginning of a JS object. | 78 // Beginning of a JS object. |
| 77 kBeginJSObject = 'o', | 79 kBeginJSObject = 'o', |
| 78 // End of a JS object. numProperties:uint32_t | 80 // End of a JS object. numProperties:uint32_t |
| 79 kEndJSObject = '{', | 81 kEndJSObject = '{', |
| 80 // Beginning of a sparse JS array. length:uint32_t | 82 // Beginning of a sparse JS array. length:uint32_t |
| 81 // Elements and properties are written as key/value pairs, like objects. | 83 // Elements and properties are written as key/value pairs, like objects. |
| 82 kBeginSparseJSArray = 'a', | 84 kBeginSparseJSArray = 'a', |
| 83 // End of a sparse JS array. numProperties:uint32_t length:uint32_t | 85 // End of a sparse JS array. numProperties:uint32_t length:uint32_t |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 }; | 155 }; |
| 154 | 156 |
| 155 } // namespace | 157 } // namespace |
| 156 | 158 |
| 157 ValueSerializer::ValueSerializer(Isolate* isolate, | 159 ValueSerializer::ValueSerializer(Isolate* isolate, |
| 158 v8::ValueSerializer::Delegate* delegate) | 160 v8::ValueSerializer::Delegate* delegate) |
| 159 : isolate_(isolate), | 161 : isolate_(isolate), |
| 160 delegate_(delegate), | 162 delegate_(delegate), |
| 161 zone_(isolate->allocator(), ZONE_NAME), | 163 zone_(isolate->allocator(), ZONE_NAME), |
| 162 id_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)), | 164 id_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)), |
| 163 array_buffer_transfer_map_(isolate->heap(), | 165 array_buffer_transfer_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)), |
| 164 ZoneAllocationPolicy(&zone_)) {} | 166 long_string_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)) {} |
| 165 | 167 |
| 166 ValueSerializer::~ValueSerializer() { | 168 ValueSerializer::~ValueSerializer() { |
| 167 if (buffer_) { | 169 if (buffer_) { |
| 168 if (delegate_) { | 170 if (delegate_) { |
| 169 delegate_->FreeBufferMemory(buffer_); | 171 delegate_->FreeBufferMemory(buffer_); |
| 170 } else { | 172 } else { |
| 171 free(buffer_); | 173 free(buffer_); |
| 172 } | 174 } |
| 173 } | 175 } |
| 174 } | 176 } |
| (...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 Handle<JSArrayBuffer> buffer( | 336 Handle<JSArrayBuffer> buffer( |
| 335 view->IsJSTypedArray() | 337 view->IsJSTypedArray() |
| 336 ? Handle<JSTypedArray>::cast(view)->GetBuffer() | 338 ? Handle<JSTypedArray>::cast(view)->GetBuffer() |
| 337 : handle(JSArrayBuffer::cast(view->buffer()), isolate_)); | 339 : handle(JSArrayBuffer::cast(view->buffer()), isolate_)); |
| 338 if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>(); | 340 if (!WriteJSReceiver(buffer).FromMaybe(false)) return Nothing<bool>(); |
| 339 } | 341 } |
| 340 return WriteJSReceiver(view); | 342 return WriteJSReceiver(view); |
| 341 } | 343 } |
| 342 default: | 344 default: |
| 343 if (object->IsString()) { | 345 if (object->IsString()) { |
| 344 WriteString(Handle<String>::cast(object)); | 346 return WriteString(Handle<String>::cast(object)); |
| 345 return ThrowIfOutOfMemory(); | |
| 346 } else if (object->IsJSReceiver()) { | 347 } else if (object->IsJSReceiver()) { |
| 347 return WriteJSReceiver(Handle<JSReceiver>::cast(object)); | 348 return WriteJSReceiver(Handle<JSReceiver>::cast(object)); |
| 348 } else { | 349 } else { |
| 349 ThrowDataCloneError(MessageTemplate::kDataCloneError, object); | 350 ThrowDataCloneError(MessageTemplate::kDataCloneError, object); |
| 350 return Nothing<bool>(); | 351 return Nothing<bool>(); |
| 351 } | 352 } |
| 352 } | 353 } |
| 353 } | 354 } |
| 354 | 355 |
| 355 void ValueSerializer::WriteOddball(Oddball* oddball) { | 356 void ValueSerializer::WriteOddball(Oddball* oddball) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 378 static_assert(kSmiValueSize <= 32, "Expected SMI <= 32 bits."); | 379 static_assert(kSmiValueSize <= 32, "Expected SMI <= 32 bits."); |
| 379 WriteTag(SerializationTag::kInt32); | 380 WriteTag(SerializationTag::kInt32); |
| 380 WriteZigZag<int32_t>(smi->value()); | 381 WriteZigZag<int32_t>(smi->value()); |
| 381 } | 382 } |
| 382 | 383 |
| 383 void ValueSerializer::WriteHeapNumber(HeapNumber* number) { | 384 void ValueSerializer::WriteHeapNumber(HeapNumber* number) { |
| 384 WriteTag(SerializationTag::kDouble); | 385 WriteTag(SerializationTag::kDouble); |
| 385 WriteDouble(number->value()); | 386 WriteDouble(number->value()); |
| 386 } | 387 } |
| 387 | 388 |
| 388 void ValueSerializer::WriteString(Handle<String> string) { | 389 Maybe<bool> ValueSerializer::WriteString(Handle<String> string) { |
| 390 if (long_string_threshold_ >= 0 && |
| 391 V8_UNLIKELY(string->length() >= long_string_threshold_)) { |
| 392 uint32_t* entry = long_string_map_.Find(string); |
| 393 if (!entry) { |
| 394 entry = long_string_map_.Get(string); |
| 395 Maybe<uint32_t> index = delegate_->GetLongStringId( |
| 396 reinterpret_cast<v8::Isolate*>(isolate_), Utils::ToLocal(string)); |
| 397 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>()); |
| 398 *entry = index.FromJust(); |
| 399 } |
| 400 WriteTag(SerializationTag::kLongString); |
| 401 WriteVarint(*entry); |
| 402 return ThrowIfOutOfMemory(); |
| 403 } |
| 404 |
| 389 string = String::Flatten(string); | 405 string = String::Flatten(string); |
| 390 DisallowHeapAllocation no_gc; | 406 DisallowHeapAllocation no_gc; |
| 391 String::FlatContent flat = string->GetFlatContent(); | 407 String::FlatContent flat = string->GetFlatContent(); |
| 392 DCHECK(flat.IsFlat()); | 408 DCHECK(flat.IsFlat()); |
| 393 if (flat.IsOneByte()) { | 409 if (flat.IsOneByte()) { |
| 394 Vector<const uint8_t> chars = flat.ToOneByteVector(); | 410 Vector<const uint8_t> chars = flat.ToOneByteVector(); |
| 395 WriteTag(SerializationTag::kOneByteString); | 411 WriteTag(SerializationTag::kOneByteString); |
| 396 WriteOneByteString(chars); | 412 WriteOneByteString(chars); |
| 397 } else if (flat.IsTwoByte()) { | 413 } else if (flat.IsTwoByte()) { |
| 398 Vector<const uc16> chars = flat.ToUC16Vector(); | 414 Vector<const uc16> chars = flat.ToUC16Vector(); |
| 399 uint32_t byte_length = chars.length() * sizeof(uc16); | 415 uint32_t byte_length = chars.length() * sizeof(uc16); |
| 400 // The existing reading code expects 16-byte strings to be aligned. | 416 // The existing reading code expects 16-byte strings to be aligned. |
| 401 if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1) | 417 if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1) |
| 402 WriteTag(SerializationTag::kPadding); | 418 WriteTag(SerializationTag::kPadding); |
| 403 WriteTag(SerializationTag::kTwoByteString); | 419 WriteTag(SerializationTag::kTwoByteString); |
| 404 WriteTwoByteString(chars); | 420 WriteTwoByteString(chars); |
| 405 } else { | 421 } else { |
| 406 UNREACHABLE(); | 422 UNREACHABLE(); |
| 407 } | 423 } |
| 424 return ThrowIfOutOfMemory(); |
| 408 } | 425 } |
| 409 | 426 |
| 410 Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { | 427 Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) { |
| 411 // If the object has already been serialized, just write its ID. | 428 // If the object has already been serialized, just write its ID. |
| 412 uint32_t* id_map_entry = id_map_.Get(receiver); | 429 uint32_t* id_map_entry = id_map_.Get(receiver); |
| 413 if (uint32_t id = *id_map_entry) { | 430 if (uint32_t id = *id_map_entry) { |
| 414 WriteTag(SerializationTag::kObjectReference); | 431 WriteTag(SerializationTag::kObjectReference); |
| 415 WriteVarint(id - 1); | 432 WriteVarint(id - 1); |
| 416 return ThrowIfOutOfMemory(); | 433 return ThrowIfOutOfMemory(); |
| 417 } | 434 } |
| (...skipping 644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1062 Handle<SeededNumberDictionary> new_dictionary = | 1079 Handle<SeededNumberDictionary> new_dictionary = |
| 1063 SeededNumberDictionary::AtNumberPut(dictionary, transfer_id, array_buffer, | 1080 SeededNumberDictionary::AtNumberPut(dictionary, transfer_id, array_buffer, |
| 1064 not_a_prototype_holder); | 1081 not_a_prototype_holder); |
| 1065 if (!new_dictionary.is_identical_to(dictionary)) { | 1082 if (!new_dictionary.is_identical_to(dictionary)) { |
| 1066 GlobalHandles::Destroy(Handle<Object>::cast(dictionary).location()); | 1083 GlobalHandles::Destroy(Handle<Object>::cast(dictionary).location()); |
| 1067 array_buffer_transfer_map_ = Handle<SeededNumberDictionary>::cast( | 1084 array_buffer_transfer_map_ = Handle<SeededNumberDictionary>::cast( |
| 1068 isolate_->global_handles()->Create(*new_dictionary)); | 1085 isolate_->global_handles()->Create(*new_dictionary)); |
| 1069 } | 1086 } |
| 1070 } | 1087 } |
| 1071 | 1088 |
| 1089 void ValueDeserializer::TransferLongString(uint32_t transfer_id, |
| 1090 Handle<String> string) { |
| 1091 if (long_string_map_.is_null()) { |
| 1092 long_string_map_ = |
| 1093 Handle<SeededNumberDictionary>::cast(isolate_->global_handles()->Create( |
| 1094 *SeededNumberDictionary::New(isolate_, 0))); |
| 1095 } |
| 1096 Handle<SeededNumberDictionary> dictionary = |
| 1097 long_string_map_.ToHandleChecked(); |
| 1098 Handle<JSObject> not_a_prototype_holder; |
| 1099 Handle<SeededNumberDictionary> new_dictionary = |
| 1100 SeededNumberDictionary::AtNumberPut(dictionary, transfer_id, string, |
| 1101 not_a_prototype_holder); |
| 1102 if (!new_dictionary.is_identical_to(dictionary)) { |
| 1103 GlobalHandles::Destroy(Handle<Object>::cast(dictionary).location()); |
| 1104 long_string_map_ = Handle<SeededNumberDictionary>::cast( |
| 1105 isolate_->global_handles()->Create(*new_dictionary)); |
| 1106 } |
| 1107 } |
| 1108 |
| 1072 MaybeHandle<Object> ValueDeserializer::ReadObject() { | 1109 MaybeHandle<Object> ValueDeserializer::ReadObject() { |
| 1073 MaybeHandle<Object> result = ReadObjectInternal(); | 1110 MaybeHandle<Object> result = ReadObjectInternal(); |
| 1074 | 1111 |
| 1075 // ArrayBufferView is special in that it consumes the value before it, even | 1112 // ArrayBufferView is special in that it consumes the value before it, even |
| 1076 // after format version 0. | 1113 // after format version 0. |
| 1077 Handle<Object> object; | 1114 Handle<Object> object; |
| 1078 SerializationTag tag; | 1115 SerializationTag tag; |
| 1079 if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) && | 1116 if (result.ToHandle(&object) && V8_UNLIKELY(object->IsJSArrayBuffer()) && |
| 1080 PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) { | 1117 PeekTag().To(&tag) && tag == SerializationTag::kArrayBufferView) { |
| 1081 ConsumeTag(SerializationTag::kArrayBufferView); | 1118 ConsumeTag(SerializationTag::kArrayBufferView); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1122 Maybe<double> number = ReadDouble(); | 1159 Maybe<double> number = ReadDouble(); |
| 1123 if (number.IsNothing()) return MaybeHandle<Object>(); | 1160 if (number.IsNothing()) return MaybeHandle<Object>(); |
| 1124 return isolate_->factory()->NewNumber(number.FromJust(), pretenure_); | 1161 return isolate_->factory()->NewNumber(number.FromJust(), pretenure_); |
| 1125 } | 1162 } |
| 1126 case SerializationTag::kUtf8String: | 1163 case SerializationTag::kUtf8String: |
| 1127 return ReadUtf8String(); | 1164 return ReadUtf8String(); |
| 1128 case SerializationTag::kOneByteString: | 1165 case SerializationTag::kOneByteString: |
| 1129 return ReadOneByteString(); | 1166 return ReadOneByteString(); |
| 1130 case SerializationTag::kTwoByteString: | 1167 case SerializationTag::kTwoByteString: |
| 1131 return ReadTwoByteString(); | 1168 return ReadTwoByteString(); |
| 1169 case SerializationTag::kLongString: |
| 1170 return ReadLongString(); |
| 1132 case SerializationTag::kObjectReference: { | 1171 case SerializationTag::kObjectReference: { |
| 1133 uint32_t id; | 1172 uint32_t id; |
| 1134 if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>(); | 1173 if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>(); |
| 1135 return GetObjectWithID(id); | 1174 return GetObjectWithID(id); |
| 1136 } | 1175 } |
| 1137 case SerializationTag::kBeginJSObject: | 1176 case SerializationTag::kBeginJSObject: |
| 1138 return ReadJSObject(); | 1177 return ReadJSObject(); |
| 1139 case SerializationTag::kBeginSparseJSArray: | 1178 case SerializationTag::kBeginSparseJSArray: |
| 1140 return ReadSparseJSArray(); | 1179 return ReadSparseJSArray(); |
| 1141 case SerializationTag::kBeginDenseJSArray: | 1180 case SerializationTag::kBeginDenseJSArray: |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1234 .ToHandle(&string)) { | 1273 .ToHandle(&string)) { |
| 1235 return MaybeHandle<String>(); | 1274 return MaybeHandle<String>(); |
| 1236 } | 1275 } |
| 1237 | 1276 |
| 1238 // Copy the bytes directly into the new string. | 1277 // Copy the bytes directly into the new string. |
| 1239 // Warning: this uses host endianness. | 1278 // Warning: this uses host endianness. |
| 1240 memcpy(string->GetChars(), bytes.begin(), bytes.length()); | 1279 memcpy(string->GetChars(), bytes.begin(), bytes.length()); |
| 1241 return string; | 1280 return string; |
| 1242 } | 1281 } |
| 1243 | 1282 |
| 1283 MaybeHandle<String> ValueDeserializer::ReadLongString() { |
| 1284 uint32_t transfer_id; |
| 1285 Handle<SeededNumberDictionary> transfer_map; |
| 1286 if (!ReadVarint<uint32_t>().To(&transfer_id) || |
| 1287 !long_string_map_.ToHandle(&transfer_map)) { |
| 1288 return MaybeHandle<String>(); |
| 1289 } |
| 1290 int index = transfer_map->FindEntry(isolate_, transfer_id); |
| 1291 if (index == SeededNumberDictionary::kNotFound) { |
| 1292 return MaybeHandle<String>(); |
| 1293 } |
| 1294 return handle(String::cast(transfer_map->ValueAt(index)), isolate_); |
| 1295 } |
| 1296 |
| 1244 bool ValueDeserializer::ReadExpectedString(Handle<String> expected) { | 1297 bool ValueDeserializer::ReadExpectedString(Handle<String> expected) { |
| 1245 // In the case of failure, the position in the stream is reset. | 1298 // In the case of failure, the position in the stream is reset. |
| 1246 const uint8_t* original_position = position_; | 1299 const uint8_t* original_position = position_; |
| 1247 | 1300 |
| 1248 SerializationTag tag; | 1301 SerializationTag tag; |
| 1249 uint32_t byte_length; | 1302 uint32_t byte_length; |
| 1250 Vector<const uint8_t> bytes; | 1303 Vector<const uint8_t> bytes; |
| 1251 if (!ReadTag().To(&tag) || !ReadVarint<uint32_t>().To(&byte_length) || | 1304 if (!ReadTag().To(&tag) || !ReadVarint<uint32_t>().To(&byte_length) || |
| 1252 byte_length > | 1305 byte_length > |
| 1253 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) || | 1306 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) || |
| (...skipping 757 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2011 if (stack.size() != 1) { | 2064 if (stack.size() != 1) { |
| 2012 isolate_->Throw(*isolate_->factory()->NewError( | 2065 isolate_->Throw(*isolate_->factory()->NewError( |
| 2013 MessageTemplate::kDataCloneDeserializationError)); | 2066 MessageTemplate::kDataCloneDeserializationError)); |
| 2014 return MaybeHandle<Object>(); | 2067 return MaybeHandle<Object>(); |
| 2015 } | 2068 } |
| 2016 return scope.CloseAndEscape(stack[0]); | 2069 return scope.CloseAndEscape(stack[0]); |
| 2017 } | 2070 } |
| 2018 | 2071 |
| 2019 } // namespace internal | 2072 } // namespace internal |
| 2020 } // namespace v8 | 2073 } // namespace v8 |
| OLD | NEW |