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

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

Issue 2768923002: WIP: Allow ValueSerializer clients to transfer long strings out of band.
Patch Set: Created 3 years, 9 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') | no next file » | 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"
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/value-serializer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698