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

Unified Diff: src/value-serializer.cc

Issue 2245753002: Blink-compatible serialization of strings. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@vs2
Patch Set: explicit cast to actually make it an unsigned comparison Created 4 years, 4 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/value-serializer.cc
diff --git a/src/value-serializer.cc b/src/value-serializer.cc
index cf76ad25ed9d7e1887f52644a12f2bd3df524ff9..8358b66b66d9f79dfc9e885e05865b14e341bc44 100644
--- a/src/value-serializer.cc
+++ b/src/value-serializer.cc
@@ -18,6 +18,18 @@ namespace internal {
static const uint32_t kLatestVersion = 9;
+template <typename T>
+static size_t BytesNeededForVarint(T value) {
+ static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
+ "Only unsigned integer types can be written as varints.");
+ size_t result = 0;
+ do {
+ result++;
+ value >>= 7;
+ } while (value);
+ return result;
+}
+
enum class SerializationTag : uint8_t {
// version:uint32_t (if at beginning of data, sets version > 0)
kVersion = 0xFF,
@@ -39,6 +51,9 @@ enum class SerializationTag : uint8_t {
// Number represented as a 64-bit double.
// Host byte order is used (N.B. this makes the format non-portable).
kDouble = 'N',
+ // byteLength:uint32_t, then raw data
+ kUtf8String = 'S',
+ kTwoByteString = 'c',
};
ValueSerializer::ValueSerializer() {}
@@ -92,6 +107,24 @@ void ValueSerializer::WriteDouble(double value) {
reinterpret_cast<const uint8_t*>(&value + 1));
}
+void ValueSerializer::WriteOneByteString(Vector<const uint8_t> chars) {
+ WriteVarint<uint32_t>(chars.length());
+ buffer_.insert(buffer_.end(), chars.begin(), chars.end());
+}
+
+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()));
+}
+
+uint8_t* ValueSerializer::ReserveRawBytes(size_t bytes) {
+ auto old_size = buffer_.size();
+ buffer_.resize(buffer_.size() + bytes);
+ return &buffer_[old_size];
+}
+
Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
if (object->IsSmi()) {
WriteSmi(Smi::cast(*object));
@@ -108,6 +141,10 @@ Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
WriteHeapNumber(HeapNumber::cast(*object));
return Just(true);
default:
+ if (object->IsString()) {
+ WriteString(Handle<String>::cast(object));
+ return Just(true);
+ }
UNIMPLEMENTED();
return Nothing<bool>();
}
@@ -146,6 +183,41 @@ void ValueSerializer::WriteHeapNumber(HeapNumber* number) {
WriteDouble(number->value());
}
+void ValueSerializer::WriteString(Handle<String> string) {
+ string = String::Flatten(string);
+ DisallowHeapAllocation no_gc;
+ String::FlatContent flat = string->GetFlatContent();
+ DCHECK(flat.IsFlat());
+ if (flat.IsOneByte()) {
+ // The existing format uses UTF-8, rather than Latin-1. As a result we must
+ // to do work to encode strings that have characters outside ASCII.
+ // TODO(jbroman): In a future format version, consider adding a tag for
+ // Latin-1 strings, so that this can be skipped.
+ WriteTag(SerializationTag::kUtf8String);
+ Vector<const uint8_t> chars = flat.ToOneByteVector();
+ if (String::IsAscii(chars.begin(), chars.length())) {
+ WriteOneByteString(chars);
+ } else {
+ v8::Local<v8::String> api_string = Utils::ToLocal(string);
+ uint32_t utf8_length = api_string->Utf8Length();
+ WriteVarint(utf8_length);
+ api_string->WriteUtf8(
+ reinterpret_cast<char*>(ReserveRawBytes(utf8_length)), utf8_length,
+ nullptr, v8::String::NO_NULL_TERMINATION);
+ }
+ } else if (flat.IsTwoByte()) {
+ 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)
+ WriteTag(SerializationTag::kPadding);
+ WriteTag(SerializationTag::kTwoByteString);
+ WriteTwoByteString(chars);
+ } else {
+ UNREACHABLE();
+ }
+}
+
ValueDeserializer::ValueDeserializer(Isolate* isolate,
Vector<const uint8_t> data)
: isolate_(isolate),
@@ -223,6 +295,13 @@ Maybe<double> ValueDeserializer::ReadDouble() {
return Just(value);
}
+Maybe<Vector<const uint8_t>> ValueDeserializer::ReadRawBytes(int size) {
+ if (size > end_ - position_) return Nothing<Vector<const uint8_t>>();
+ const uint8_t* start = position_;
+ position_ += size;
+ return Just(Vector<const uint8_t>(start, size));
+}
+
MaybeHandle<Object> ValueDeserializer::ReadObject() {
SerializationTag tag;
if (!ReadTag().To(&tag)) return MaybeHandle<Object>();
@@ -254,10 +333,49 @@ MaybeHandle<Object> ValueDeserializer::ReadObject() {
if (number.IsNothing()) return MaybeHandle<Object>();
return isolate_->factory()->NewNumber(number.FromJust());
}
+ case SerializationTag::kUtf8String:
+ return ReadUtf8String();
+ case SerializationTag::kTwoByteString:
+ return ReadTwoByteString();
default:
return MaybeHandle<Object>();
}
}
+MaybeHandle<String> ValueDeserializer::ReadUtf8String() {
+ uint32_t utf8_length;
+ Vector<const uint8_t> utf8_bytes;
+ if (!ReadVarint<uint32_t>().To(&utf8_length) ||
+ utf8_length >
+ static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
+ !ReadRawBytes(utf8_length).To(&utf8_bytes))
+ return MaybeHandle<String>();
+ return isolate_->factory()->NewStringFromUtf8(
+ Vector<const char>::cast(utf8_bytes));
+}
+
+MaybeHandle<String> ValueDeserializer::ReadTwoByteString() {
+ uint32_t byte_length;
+ Vector<const uint8_t> bytes;
+ if (!ReadVarint<uint32_t>().To(&byte_length) ||
+ byte_length >
+ static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
+ byte_length % sizeof(uc16) != 0 || !ReadRawBytes(byte_length).To(&bytes))
+ return MaybeHandle<String>();
+
+ // Allocate an uninitialized string so that we can do a raw memcpy into the
+ // string on the heap (regardless of alignment).
+ Handle<SeqTwoByteString> string;
+ if (!isolate_->factory()
+ ->NewRawTwoByteString(byte_length / sizeof(uc16))
+ .ToHandle(&string))
+ return MaybeHandle<String>();
+
+ // Copy the bytes directly into the new string.
+ // Warning: this uses host endianness.
+ memcpy(string->GetChars(), bytes.begin(), bytes.length());
+ return string;
+}
+
} // namespace internal
} // namespace v8
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698