Index: src/value-serializer.cc |
diff --git a/src/value-serializer.cc b/src/value-serializer.cc |
index 756732043a404595d9412b9079d64678416906e8..bbfb2c77e038e5fe2051ec406e0ae66a15b9f045 100644 |
--- a/src/value-serializer.cc |
+++ b/src/value-serializer.cc |
@@ -92,12 +92,15 @@ enum class SerializationTag : uint8_t { |
kEndJSSet = ',', |
// Array buffer. byteLength:uint32_t, then raw data. |
kArrayBuffer = 'B', |
+ // Array buffer (transferred). transferID:uint32_t |
+ kArrayBufferTransfer = 't', |
}; |
ValueSerializer::ValueSerializer(Isolate* isolate) |
: isolate_(isolate), |
zone_(isolate->allocator()), |
- id_map_(isolate->heap(), &zone_) {} |
+ id_map_(isolate->heap(), &zone_), |
+ array_buffer_transfer_map_(isolate->heap(), &zone_) {} |
ValueSerializer::~ValueSerializer() {} |
@@ -172,6 +175,12 @@ uint8_t* ValueSerializer::ReserveRawBytes(size_t bytes) { |
return &buffer_[old_size]; |
} |
+void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id, |
+ Handle<JSArrayBuffer> array_buffer) { |
+ DCHECK(!array_buffer_transfer_map_.Find(array_buffer)); |
+ array_buffer_transfer_map_.Set(array_buffer, transfer_id); |
+} |
+ |
Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) { |
if (object->IsSmi()) { |
WriteSmi(Smi::cast(*object)); |
@@ -500,6 +509,14 @@ Maybe<bool> ValueSerializer::WriteJSSet(Handle<JSSet> set) { |
} |
Maybe<bool> ValueSerializer::WriteJSArrayBuffer(JSArrayBuffer* array_buffer) { |
+ uint32_t* transfer_entry = array_buffer_transfer_map_.Find(array_buffer); |
+ if (transfer_entry) { |
+ DCHECK(array_buffer->was_neutered()); |
+ WriteTag(SerializationTag::kArrayBufferTransfer); |
+ WriteVarint(*transfer_entry); |
+ return Just(true); |
+ } |
+ |
if (array_buffer->was_neutered()) return Nothing<bool>(); |
double byte_length = array_buffer->byte_length()->Number(); |
if (byte_length > std::numeric_limits<uint32_t>::max()) { |
@@ -550,6 +567,11 @@ ValueDeserializer::ValueDeserializer(Isolate* isolate, |
ValueDeserializer::~ValueDeserializer() { |
GlobalHandles::Destroy(Handle<Object>::cast(id_map_).location()); |
+ |
+ Handle<Object> transfer_map_handle; |
+ if (array_buffer_transfer_map_.ToHandle(&transfer_map_handle)) { |
+ GlobalHandles::Destroy(transfer_map_handle.location()); |
+ } |
} |
Maybe<bool> ValueDeserializer::ReadHeader() { |
@@ -645,6 +667,26 @@ Maybe<Vector<const uint8_t>> ValueDeserializer::ReadRawBytes(int size) { |
return Just(Vector<const uint8_t>(start, size)); |
} |
+void ValueDeserializer::TransferArrayBuffer( |
+ uint32_t transfer_id, Handle<JSArrayBuffer> array_buffer) { |
+ if (array_buffer_transfer_map_.is_null()) { |
+ array_buffer_transfer_map_ = |
+ Handle<SeededNumberDictionary>::cast(isolate_->global_handles()->Create( |
+ *SeededNumberDictionary::New(isolate_, 0))); |
+ } |
+ Handle<SeededNumberDictionary> dictionary = |
+ array_buffer_transfer_map_.ToHandleChecked(); |
+ const bool used_as_prototype = false; |
+ Handle<SeededNumberDictionary> new_dictionary = |
+ SeededNumberDictionary::AtNumberPut(dictionary, transfer_id, array_buffer, |
+ used_as_prototype); |
+ if (!new_dictionary.is_identical_to(dictionary)) { |
+ GlobalHandles::Destroy(Handle<Object>::cast(dictionary).location()); |
+ array_buffer_transfer_map_ = Handle<SeededNumberDictionary>::cast( |
+ isolate_->global_handles()->Create(*new_dictionary)); |
+ } |
+} |
+ |
MaybeHandle<Object> ValueDeserializer::ReadObject() { |
SerializationTag tag; |
if (!ReadTag().To(&tag)) return MaybeHandle<Object>(); |
@@ -706,6 +748,8 @@ MaybeHandle<Object> ValueDeserializer::ReadObject() { |
return ReadJSSet(); |
case SerializationTag::kArrayBuffer: |
return ReadJSArrayBuffer(); |
+ case SerializationTag::kArrayBufferTransfer: |
+ return ReadTransferredJSArrayBuffer(); |
default: |
return MaybeHandle<Object>(); |
} |
@@ -992,6 +1036,24 @@ MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadJSArrayBuffer() { |
return array_buffer; |
} |
+MaybeHandle<JSArrayBuffer> ValueDeserializer::ReadTransferredJSArrayBuffer() { |
+ uint32_t id = next_id_++; |
+ uint32_t transfer_id; |
+ Handle<SeededNumberDictionary> transfer_map; |
+ if (!ReadVarint<uint32_t>().To(&transfer_id) || |
+ !array_buffer_transfer_map_.ToHandle(&transfer_map)) { |
+ return MaybeHandle<JSArrayBuffer>(); |
+ } |
+ int index = transfer_map->FindEntry(isolate_, transfer_id); |
+ if (index == SeededNumberDictionary::kNotFound) { |
+ return MaybeHandle<JSArrayBuffer>(); |
+ } |
+ Handle<JSArrayBuffer> array_buffer( |
+ JSArrayBuffer::cast(transfer_map->ValueAt(index)), isolate_); |
+ AddObjectWithID(id, array_buffer); |
+ return array_buffer; |
+} |
+ |
Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties( |
Handle<JSObject> object, SerializationTag end_tag) { |
for (uint32_t num_properties = 0;; num_properties++) { |