Commit 94142ed8 authored by jbroman's avatar jbroman Committed by Commit bot

ValueSerializer: Replace use of std::vector with a delegate-allocated buffer.

BUG=chromium:148757

Review-Url: https://codereview.chromium.org/2492943002
Cr-Commit-Position: refs/heads/master@{#40943}
parent 87ca9283
...@@ -1711,6 +1711,19 @@ class V8_EXPORT ValueSerializer { ...@@ -1711,6 +1711,19 @@ class V8_EXPORT ValueSerializer {
* Nothing<bool>() returned. * Nothing<bool>() returned.
*/ */
virtual Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object); virtual Maybe<bool> WriteHostObject(Isolate* isolate, Local<Object> object);
/*
* Allocates memory for the buffer of at least the size provided. The actual
* size (which may be greater or equal) is written to |actual_size|. If no
* buffer has been allocated yet, nullptr will be provided.
*/
virtual void* ReallocateBufferMemory(void* old_buffer, size_t size,
size_t* actual_size);
/*
* Frees a buffer allocated with |ReallocateBufferMemory|.
*/
virtual void FreeBufferMemory(void* buffer);
}; };
explicit ValueSerializer(Isolate* isolate); explicit ValueSerializer(Isolate* isolate);
...@@ -1732,7 +1745,15 @@ class V8_EXPORT ValueSerializer { ...@@ -1732,7 +1745,15 @@ class V8_EXPORT ValueSerializer {
* Returns the stored data. This serializer should not be used once the buffer * Returns the stored data. This serializer should not be used once the buffer
* is released. The contents are undefined if a previous write has failed. * is released. The contents are undefined if a previous write has failed.
*/ */
std::vector<uint8_t> ReleaseBuffer(); V8_DEPRECATE_SOON("Use Release()", std::vector<uint8_t> ReleaseBuffer());
/*
* Returns the stored data (allocated using the delegate's
* AllocateBufferMemory) and its size. This serializer should not be used once
* the buffer is released. The contents are undefined if a previous write has
* failed.
*/
V8_WARN_UNUSED_RESULT std::pair<uint8_t*, size_t> Release();
/* /*
* Marks an ArrayBuffer as havings its contents transferred out of band. * Marks an ArrayBuffer as havings its contents transferred out of band.
......
...@@ -2973,6 +2973,17 @@ Maybe<bool> ValueSerializer::Delegate::WriteHostObject(Isolate* v8_isolate, ...@@ -2973,6 +2973,17 @@ Maybe<bool> ValueSerializer::Delegate::WriteHostObject(Isolate* v8_isolate,
return Nothing<bool>(); return Nothing<bool>();
} }
void* ValueSerializer::Delegate::ReallocateBufferMemory(void* old_buffer,
size_t size,
size_t* actual_size) {
*actual_size = size;
return realloc(old_buffer, size);
}
void ValueSerializer::Delegate::FreeBufferMemory(void* buffer) {
return free(buffer);
}
struct ValueSerializer::PrivateData { struct ValueSerializer::PrivateData {
explicit PrivateData(i::Isolate* i, ValueSerializer::Delegate* delegate) explicit PrivateData(i::Isolate* i, ValueSerializer::Delegate* delegate)
: isolate(i), serializer(i, delegate) {} : isolate(i), serializer(i, delegate) {}
...@@ -3005,6 +3016,10 @@ std::vector<uint8_t> ValueSerializer::ReleaseBuffer() { ...@@ -3005,6 +3016,10 @@ std::vector<uint8_t> ValueSerializer::ReleaseBuffer() {
return private_->serializer.ReleaseBuffer(); return private_->serializer.ReleaseBuffer();
} }
std::pair<uint8_t*, size_t> ValueSerializer::Release() {
return private_->serializer.Release();
}
void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id, void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id,
Local<ArrayBuffer> array_buffer) { Local<ArrayBuffer> array_buffer) {
private_->serializer.TransferArrayBuffer(transfer_id, private_->serializer.TransferArrayBuffer(transfer_id,
......
...@@ -148,7 +148,15 @@ ValueSerializer::ValueSerializer(Isolate* isolate, ...@@ -148,7 +148,15 @@ ValueSerializer::ValueSerializer(Isolate* isolate,
id_map_(isolate->heap(), &zone_), id_map_(isolate->heap(), &zone_),
array_buffer_transfer_map_(isolate->heap(), &zone_) {} array_buffer_transfer_map_(isolate->heap(), &zone_) {}
ValueSerializer::~ValueSerializer() {} ValueSerializer::~ValueSerializer() {
if (buffer_) {
if (delegate_) {
delegate_->FreeBufferMemory(buffer_);
} else {
free(buffer_);
}
}
}
void ValueSerializer::WriteHeader() { void ValueSerializer::WriteHeader() {
WriteTag(SerializationTag::kVersion); WriteTag(SerializationTag::kVersion);
...@@ -156,7 +164,8 @@ void ValueSerializer::WriteHeader() { ...@@ -156,7 +164,8 @@ void ValueSerializer::WriteHeader() {
} }
void ValueSerializer::WriteTag(SerializationTag tag) { void ValueSerializer::WriteTag(SerializationTag tag) {
buffer_.push_back(static_cast<uint8_t>(tag)); uint8_t raw_tag = static_cast<uint8_t>(tag);
WriteRawBytes(&raw_tag, sizeof(raw_tag));
} }
template <typename T> template <typename T>
...@@ -175,7 +184,7 @@ void ValueSerializer::WriteVarint(T value) { ...@@ -175,7 +184,7 @@ void ValueSerializer::WriteVarint(T value) {
value >>= 7; value >>= 7;
} while (value); } while (value);
*(next_byte - 1) &= 0x7f; *(next_byte - 1) &= 0x7f;
buffer_.insert(buffer_.end(), stack_buffer, next_byte); WriteRawBytes(stack_buffer, next_byte - stack_buffer);
} }
template <typename T> template <typename T>
...@@ -193,34 +202,50 @@ void ValueSerializer::WriteZigZag(T value) { ...@@ -193,34 +202,50 @@ void ValueSerializer::WriteZigZag(T value) {
void ValueSerializer::WriteDouble(double value) { void ValueSerializer::WriteDouble(double value) {
// Warning: this uses host endianness. // Warning: this uses host endianness.
buffer_.insert(buffer_.end(), reinterpret_cast<const uint8_t*>(&value), WriteRawBytes(&value, sizeof(value));
reinterpret_cast<const uint8_t*>(&value + 1));
} }
void ValueSerializer::WriteOneByteString(Vector<const uint8_t> chars) { void ValueSerializer::WriteOneByteString(Vector<const uint8_t> chars) {
WriteVarint<uint32_t>(chars.length()); WriteVarint<uint32_t>(chars.length());
buffer_.insert(buffer_.end(), chars.begin(), chars.end()); WriteRawBytes(chars.begin(), chars.length() * sizeof(uint8_t));
} }
void ValueSerializer::WriteTwoByteString(Vector<const uc16> chars) { void ValueSerializer::WriteTwoByteString(Vector<const uc16> chars) {
// Warning: this uses host endianness. // Warning: this uses host endianness.
WriteVarint<uint32_t>(chars.length() * sizeof(uc16)); WriteVarint<uint32_t>(chars.length() * sizeof(uc16));
buffer_.insert(buffer_.end(), reinterpret_cast<const uint8_t*>(chars.begin()), WriteRawBytes(chars.begin(), chars.length() * sizeof(uc16));
reinterpret_cast<const uint8_t*>(chars.end()));
} }
void ValueSerializer::WriteRawBytes(const void* source, size_t length) { void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
const uint8_t* begin = reinterpret_cast<const uint8_t*>(source); memcpy(ReserveRawBytes(length), source, length);
buffer_.insert(buffer_.end(), begin, begin + length);
} }
uint8_t* ValueSerializer::ReserveRawBytes(size_t bytes) { uint8_t* ValueSerializer::ReserveRawBytes(size_t bytes) {
if (!bytes) return nullptr; size_t old_size = buffer_size_;
auto old_size = buffer_.size(); size_t new_size = old_size + bytes;
buffer_.resize(buffer_.size() + bytes); if (new_size > buffer_capacity_) ExpandBuffer(new_size);
buffer_size_ = new_size;
return &buffer_[old_size]; return &buffer_[old_size];
} }
void ValueSerializer::ExpandBuffer(size_t required_capacity) {
DCHECK_GT(required_capacity, buffer_capacity_);
size_t requested_capacity =
std::max(required_capacity, buffer_capacity_ * 2) + 64;
size_t provided_capacity = 0;
void* new_buffer = nullptr;
if (delegate_) {
new_buffer = delegate_->ReallocateBufferMemory(buffer_, requested_capacity,
&provided_capacity);
} else {
new_buffer = realloc(buffer_, requested_capacity);
provided_capacity = requested_capacity;
}
DCHECK_GE(provided_capacity, requested_capacity);
buffer_ = reinterpret_cast<uint8_t*>(new_buffer);
buffer_capacity_ = provided_capacity;
}
void ValueSerializer::WriteUint32(uint32_t value) { void ValueSerializer::WriteUint32(uint32_t value) {
WriteVarint<uint32_t>(value); WriteVarint<uint32_t>(value);
} }
...@@ -229,6 +254,18 @@ void ValueSerializer::WriteUint64(uint64_t value) { ...@@ -229,6 +254,18 @@ void ValueSerializer::WriteUint64(uint64_t value) {
WriteVarint<uint64_t>(value); WriteVarint<uint64_t>(value);
} }
std::vector<uint8_t> ValueSerializer::ReleaseBuffer() {
return std::vector<uint8_t>(buffer_, buffer_ + buffer_size_);
}
std::pair<uint8_t*, size_t> ValueSerializer::Release() {
auto result = std::make_pair(buffer_, buffer_size_);
buffer_ = nullptr;
buffer_size_ = 0;
buffer_capacity_ = 0;
return result;
}
void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id, void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id,
Handle<JSArrayBuffer> array_buffer) { Handle<JSArrayBuffer> array_buffer) {
DCHECK(!array_buffer_transfer_map_.Find(array_buffer)); DCHECK(!array_buffer_transfer_map_.Find(array_buffer));
...@@ -339,7 +376,7 @@ void ValueSerializer::WriteString(Handle<String> string) { ...@@ -339,7 +376,7 @@ void ValueSerializer::WriteString(Handle<String> string) {
Vector<const uc16> chars = flat.ToUC16Vector(); Vector<const uc16> chars = flat.ToUC16Vector();
uint32_t byte_length = chars.length() * sizeof(uc16); uint32_t byte_length = chars.length() * sizeof(uc16);
// The existing reading code expects 16-byte strings to be aligned. // The existing reading code expects 16-byte strings to be aligned.
if ((buffer_.size() + 1 + BytesNeededForVarint(byte_length)) & 1) if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1)
WriteTag(SerializationTag::kPadding); WriteTag(SerializationTag::kPadding);
WriteTag(SerializationTag::kTwoByteString); WriteTag(SerializationTag::kTwoByteString);
WriteTwoByteString(chars); WriteTwoByteString(chars);
......
...@@ -59,7 +59,13 @@ class ValueSerializer { ...@@ -59,7 +59,13 @@ class ValueSerializer {
* Returns the stored data. This serializer should not be used once the buffer * Returns the stored data. This serializer should not be used once the buffer
* is released. The contents are undefined if a previous write has failed. * is released. The contents are undefined if a previous write has failed.
*/ */
std::vector<uint8_t> ReleaseBuffer() { return std::move(buffer_); } std::vector<uint8_t> ReleaseBuffer();
/*
* Returns the buffer, allocated via the delegate, and its size.
* Caller assumes ownership of the buffer.
*/
std::pair<uint8_t*, size_t> Release();
/* /*
* Marks an ArrayBuffer as havings its contents transferred out of band. * Marks an ArrayBuffer as havings its contents transferred out of band.
...@@ -79,6 +85,9 @@ class ValueSerializer { ...@@ -79,6 +85,9 @@ class ValueSerializer {
void WriteDouble(double value); void WriteDouble(double value);
private: private:
// Managing allocations of the internal buffer.
void ExpandBuffer(size_t required_capacity);
// Writing the wire format. // Writing the wire format.
void WriteTag(SerializationTag tag); void WriteTag(SerializationTag tag);
template <typename T> template <typename T>
...@@ -126,7 +135,9 @@ class ValueSerializer { ...@@ -126,7 +135,9 @@ class ValueSerializer {
Isolate* const isolate_; Isolate* const isolate_;
v8::ValueSerializer::Delegate* const delegate_; v8::ValueSerializer::Delegate* const delegate_;
std::vector<uint8_t> buffer_; uint8_t* buffer_ = nullptr;
size_t buffer_size_ = 0;
size_t buffer_capacity_ = 0;
Zone zone_; Zone zone_;
// To avoid extra lookups in the identity map, ID+1 is actually stored in the // To avoid extra lookups in the identity map, ID+1 is actually stored in the
......
...@@ -111,7 +111,10 @@ class ValueSerializerTest : public TestWithIsolate { ...@@ -111,7 +111,10 @@ class ValueSerializerTest : public TestWithIsolate {
return Nothing<std::vector<uint8_t>>(); return Nothing<std::vector<uint8_t>>();
} }
AfterEncode(); AfterEncode();
return Just(serializer.ReleaseBuffer()); std::pair<uint8_t*, size_t> buffer = serializer.Release();
std::vector<uint8_t> result(buffer.first, buffer.first + buffer.second);
free(buffer.first);
return Just(std::move(result));
} }
template <typename InputFunctor, typename EncodedDataFunctor> template <typename InputFunctor, typename EncodedDataFunctor>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment