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 {
* Nothing<bool>() returned.
*/
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);
......@@ -1732,7 +1745,15 @@ class V8_EXPORT ValueSerializer {
* 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.
*/
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.
......
......@@ -2973,6 +2973,17 @@ Maybe<bool> ValueSerializer::Delegate::WriteHostObject(Isolate* v8_isolate,
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 {
explicit PrivateData(i::Isolate* i, ValueSerializer::Delegate* delegate)
: isolate(i), serializer(i, delegate) {}
......@@ -3005,6 +3016,10 @@ std::vector<uint8_t> ValueSerializer::ReleaseBuffer() {
return private_->serializer.ReleaseBuffer();
}
std::pair<uint8_t*, size_t> ValueSerializer::Release() {
return private_->serializer.Release();
}
void ValueSerializer::TransferArrayBuffer(uint32_t transfer_id,
Local<ArrayBuffer> array_buffer) {
private_->serializer.TransferArrayBuffer(transfer_id,
......
......@@ -148,7 +148,15 @@ ValueSerializer::ValueSerializer(Isolate* isolate,
id_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() {
WriteTag(SerializationTag::kVersion);
......@@ -156,7 +164,8 @@ void ValueSerializer::WriteHeader() {
}
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>
......@@ -175,7 +184,7 @@ void ValueSerializer::WriteVarint(T value) {
value >>= 7;
} while (value);
*(next_byte - 1) &= 0x7f;
buffer_.insert(buffer_.end(), stack_buffer, next_byte);
WriteRawBytes(stack_buffer, next_byte - stack_buffer);
}
template <typename T>
......@@ -193,34 +202,50 @@ void ValueSerializer::WriteZigZag(T value) {
void ValueSerializer::WriteDouble(double value) {
// Warning: this uses host endianness.
buffer_.insert(buffer_.end(), reinterpret_cast<const uint8_t*>(&value),
reinterpret_cast<const uint8_t*>(&value + 1));
WriteRawBytes(&value, sizeof(value));
}
void ValueSerializer::WriteOneByteString(Vector<const uint8_t> chars) {
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) {
// Warning: this uses host endianness.
WriteVarint<uint32_t>(chars.length() * sizeof(uc16));
buffer_.insert(buffer_.end(), reinterpret_cast<const uint8_t*>(chars.begin()),
reinterpret_cast<const uint8_t*>(chars.end()));
WriteRawBytes(chars.begin(), chars.length() * sizeof(uc16));
}
void ValueSerializer::WriteRawBytes(const void* source, size_t length) {
const uint8_t* begin = reinterpret_cast<const uint8_t*>(source);
buffer_.insert(buffer_.end(), begin, begin + length);
memcpy(ReserveRawBytes(length), source, length);
}
uint8_t* ValueSerializer::ReserveRawBytes(size_t bytes) {
if (!bytes) return nullptr;
auto old_size = buffer_.size();
buffer_.resize(buffer_.size() + bytes);
size_t old_size = buffer_size_;
size_t new_size = old_size + bytes;
if (new_size > buffer_capacity_) ExpandBuffer(new_size);
buffer_size_ = new_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) {
WriteVarint<uint32_t>(value);
}
......@@ -229,6 +254,18 @@ void ValueSerializer::WriteUint64(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,
Handle<JSArrayBuffer> array_buffer) {
DCHECK(!array_buffer_transfer_map_.Find(array_buffer));
......@@ -339,7 +376,7 @@ void ValueSerializer::WriteString(Handle<String> string) {
Vector<const uc16> chars = flat.ToUC16Vector();
uint32_t byte_length = chars.length() * sizeof(uc16);
// 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::kTwoByteString);
WriteTwoByteString(chars);
......
......@@ -59,7 +59,13 @@ class ValueSerializer {
* 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.
*/
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.
......@@ -79,6 +85,9 @@ class ValueSerializer {
void WriteDouble(double value);
private:
// Managing allocations of the internal buffer.
void ExpandBuffer(size_t required_capacity);
// Writing the wire format.
void WriteTag(SerializationTag tag);
template <typename T>
......@@ -126,7 +135,9 @@ class ValueSerializer {
Isolate* const isolate_;
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_;
// To avoid extra lookups in the identity map, ID+1 is actually stored in the
......
......@@ -111,7 +111,10 @@ class ValueSerializerTest : public TestWithIsolate {
return Nothing<std::vector<uint8_t>>();
}
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>
......
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