| Index: src/value-serializer.cc
|
| diff --git a/src/value-serializer.cc b/src/value-serializer.cc
|
| index 4b8b454c5d6e89a509cd06b10d77d71fb75e9b7b..330ba5557b616663f5efd8f9a75762d1a7aae1b3 100644
|
| --- a/src/value-serializer.cc
|
| +++ b/src/value-serializer.cc
|
| @@ -71,6 +71,8 @@ enum class SerializationTag : uint8_t {
|
| kUtf8String = 'S',
|
| kOneByteString = '"',
|
| kTwoByteString = 'c',
|
| + // ID:uint32_t. Only used if the client requests it.
|
| + kLongString = '>',
|
| // Reference to a serialized object. objectID:uint32_t
|
| kObjectReference = '^',
|
| // Beginning of a JS object.
|
| @@ -160,8 +162,8 @@ ValueSerializer::ValueSerializer(Isolate* isolate,
|
| delegate_(delegate),
|
| zone_(isolate->allocator(), ZONE_NAME),
|
| id_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)),
|
| - array_buffer_transfer_map_(isolate->heap(),
|
| - ZoneAllocationPolicy(&zone_)) {}
|
| + array_buffer_transfer_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)),
|
| + long_string_map_(isolate->heap(), ZoneAllocationPolicy(&zone_)) {}
|
|
|
| ValueSerializer::~ValueSerializer() {
|
| if (buffer_) {
|
| @@ -341,8 +343,7 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
|
| }
|
| default:
|
| if (object->IsString()) {
|
| - WriteString(Handle<String>::cast(object));
|
| - return ThrowIfOutOfMemory();
|
| + return WriteString(Handle<String>::cast(object));
|
| } else if (object->IsJSReceiver()) {
|
| return WriteJSReceiver(Handle<JSReceiver>::cast(object));
|
| } else {
|
| @@ -385,7 +386,22 @@ void ValueSerializer::WriteHeapNumber(HeapNumber* number) {
|
| WriteDouble(number->value());
|
| }
|
|
|
| -void ValueSerializer::WriteString(Handle<String> string) {
|
| +Maybe<bool> ValueSerializer::WriteString(Handle<String> string) {
|
| + if (long_string_threshold_ >= 0 &&
|
| + V8_UNLIKELY(string->length() >= long_string_threshold_)) {
|
| + uint32_t* entry = long_string_map_.Find(string);
|
| + if (!entry) {
|
| + entry = long_string_map_.Get(string);
|
| + Maybe<uint32_t> index = delegate_->GetLongStringId(
|
| + reinterpret_cast<v8::Isolate*>(isolate_), Utils::ToLocal(string));
|
| + RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate_, Nothing<bool>());
|
| + *entry = index.FromJust();
|
| + }
|
| + WriteTag(SerializationTag::kLongString);
|
| + WriteVarint(*entry);
|
| + return ThrowIfOutOfMemory();
|
| + }
|
| +
|
| string = String::Flatten(string);
|
| DisallowHeapAllocation no_gc;
|
| String::FlatContent flat = string->GetFlatContent();
|
| @@ -405,6 +421,7 @@ void ValueSerializer::WriteString(Handle<String> string) {
|
| } else {
|
| UNREACHABLE();
|
| }
|
| + return ThrowIfOutOfMemory();
|
| }
|
|
|
| Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
|
| @@ -1069,6 +1086,26 @@ void ValueDeserializer::TransferArrayBuffer(
|
| }
|
| }
|
|
|
| +void ValueDeserializer::TransferLongString(uint32_t transfer_id,
|
| + Handle<String> string) {
|
| + if (long_string_map_.is_null()) {
|
| + long_string_map_ =
|
| + Handle<SeededNumberDictionary>::cast(isolate_->global_handles()->Create(
|
| + *SeededNumberDictionary::New(isolate_, 0)));
|
| + }
|
| + Handle<SeededNumberDictionary> dictionary =
|
| + long_string_map_.ToHandleChecked();
|
| + Handle<JSObject> not_a_prototype_holder;
|
| + Handle<SeededNumberDictionary> new_dictionary =
|
| + SeededNumberDictionary::AtNumberPut(dictionary, transfer_id, string,
|
| + not_a_prototype_holder);
|
| + if (!new_dictionary.is_identical_to(dictionary)) {
|
| + GlobalHandles::Destroy(Handle<Object>::cast(dictionary).location());
|
| + long_string_map_ = Handle<SeededNumberDictionary>::cast(
|
| + isolate_->global_handles()->Create(*new_dictionary));
|
| + }
|
| +}
|
| +
|
| MaybeHandle<Object> ValueDeserializer::ReadObject() {
|
| MaybeHandle<Object> result = ReadObjectInternal();
|
|
|
| @@ -1129,6 +1166,8 @@ MaybeHandle<Object> ValueDeserializer::ReadObjectInternal() {
|
| return ReadOneByteString();
|
| case SerializationTag::kTwoByteString:
|
| return ReadTwoByteString();
|
| + case SerializationTag::kLongString:
|
| + return ReadLongString();
|
| case SerializationTag::kObjectReference: {
|
| uint32_t id;
|
| if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>();
|
| @@ -1241,6 +1280,20 @@ MaybeHandle<String> ValueDeserializer::ReadTwoByteString() {
|
| return string;
|
| }
|
|
|
| +MaybeHandle<String> ValueDeserializer::ReadLongString() {
|
| + uint32_t transfer_id;
|
| + Handle<SeededNumberDictionary> transfer_map;
|
| + if (!ReadVarint<uint32_t>().To(&transfer_id) ||
|
| + !long_string_map_.ToHandle(&transfer_map)) {
|
| + return MaybeHandle<String>();
|
| + }
|
| + int index = transfer_map->FindEntry(isolate_, transfer_id);
|
| + if (index == SeededNumberDictionary::kNotFound) {
|
| + return MaybeHandle<String>();
|
| + }
|
| + return handle(String::cast(transfer_map->ValueAt(index)), isolate_);
|
| +}
|
| +
|
| bool ValueDeserializer::ReadExpectedString(Handle<String> expected) {
|
| // In the case of failure, the position in the stream is reset.
|
| const uint8_t* original_position = position_;
|
|
|