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

Side by Side 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 unified diff | Download patch
« no previous file with comments | « src/value-serializer.h ('k') | test/unittests/value-serializer-unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/value-serializer.h" 5 #include "src/value-serializer.h"
6 6
7 #include <type_traits> 7 #include <type_traits>
8 8
9 #include "src/base/logging.h" 9 #include "src/base/logging.h"
10 #include "src/factory.h" 10 #include "src/factory.h"
11 #include "src/handles-inl.h" 11 #include "src/handles-inl.h"
12 #include "src/isolate.h" 12 #include "src/isolate.h"
13 #include "src/objects-inl.h" 13 #include "src/objects-inl.h"
14 #include "src/objects.h" 14 #include "src/objects.h"
15 15
16 namespace v8 { 16 namespace v8 {
17 namespace internal { 17 namespace internal {
18 18
19 static const uint32_t kLatestVersion = 9; 19 static const uint32_t kLatestVersion = 9;
20 20
21 template <typename T>
22 static size_t BytesNeededForVarint(T value) {
23 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value,
24 "Only unsigned integer types can be written as varints.");
25 size_t result = 0;
26 do {
27 result++;
28 value >>= 7;
29 } while (value);
30 return result;
31 }
32
21 enum class SerializationTag : uint8_t { 33 enum class SerializationTag : uint8_t {
22 // version:uint32_t (if at beginning of data, sets version > 0) 34 // version:uint32_t (if at beginning of data, sets version > 0)
23 kVersion = 0xFF, 35 kVersion = 0xFF,
24 // ignore 36 // ignore
25 kPadding = '\0', 37 kPadding = '\0',
26 // refTableSize:uint32_t (previously used for sanity checks; safe to ignore) 38 // refTableSize:uint32_t (previously used for sanity checks; safe to ignore)
27 kVerifyObjectCount = '?', 39 kVerifyObjectCount = '?',
28 // Oddballs (no data). 40 // Oddballs (no data).
29 kUndefined = '_', 41 kUndefined = '_',
30 kNull = '0', 42 kNull = '0',
31 kTrue = 'T', 43 kTrue = 'T',
32 kFalse = 'F', 44 kFalse = 'F',
33 // Number represented as 32-bit integer, ZigZag-encoded 45 // Number represented as 32-bit integer, ZigZag-encoded
34 // (like sint32 in protobuf) 46 // (like sint32 in protobuf)
35 kInt32 = 'I', 47 kInt32 = 'I',
36 // Number represented as 32-bit unsigned integer, varint-encoded 48 // Number represented as 32-bit unsigned integer, varint-encoded
37 // (like uint32 in protobuf) 49 // (like uint32 in protobuf)
38 kUint32 = 'U', 50 kUint32 = 'U',
39 // Number represented as a 64-bit double. 51 // Number represented as a 64-bit double.
40 // Host byte order is used (N.B. this makes the format non-portable). 52 // Host byte order is used (N.B. this makes the format non-portable).
41 kDouble = 'N', 53 kDouble = 'N',
54 // byteLength:uint32_t, then raw data
55 kUtf8String = 'S',
56 kTwoByteString = 'c',
42 }; 57 };
43 58
44 ValueSerializer::ValueSerializer() {} 59 ValueSerializer::ValueSerializer() {}
45 60
46 ValueSerializer::~ValueSerializer() {} 61 ValueSerializer::~ValueSerializer() {}
47 62
48 void ValueSerializer::WriteHeader() { 63 void ValueSerializer::WriteHeader() {
49 WriteTag(SerializationTag::kVersion); 64 WriteTag(SerializationTag::kVersion);
50 WriteVarint(kLatestVersion); 65 WriteVarint(kLatestVersion);
51 } 66 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 WriteVarint((static_cast<UnsignedT>(value) << 1) ^ 100 WriteVarint((static_cast<UnsignedT>(value) << 1) ^
86 (value >> (8 * sizeof(T) - 1))); 101 (value >> (8 * sizeof(T) - 1)));
87 } 102 }
88 103
89 void ValueSerializer::WriteDouble(double value) { 104 void ValueSerializer::WriteDouble(double value) {
90 // Warning: this uses host endianness. 105 // Warning: this uses host endianness.
91 buffer_.insert(buffer_.end(), reinterpret_cast<const uint8_t*>(&value), 106 buffer_.insert(buffer_.end(), reinterpret_cast<const uint8_t*>(&value),
92 reinterpret_cast<const uint8_t*>(&value + 1)); 107 reinterpret_cast<const uint8_t*>(&value + 1));
93 } 108 }
94 109
110 void ValueSerializer::WriteOneByteString(Vector<const uint8_t> chars) {
111 WriteVarint<uint32_t>(chars.length());
112 buffer_.insert(buffer_.end(), chars.begin(), chars.end());
113 }
114
115 void ValueSerializer::WriteTwoByteString(Vector<const uc16> chars) {
116 // Warning: this uses host endianness.
117 WriteVarint<uint32_t>(chars.length() * sizeof(uc16));
118 buffer_.insert(buffer_.end(), reinterpret_cast<const uint8_t*>(chars.begin()),
119 reinterpret_cast<const uint8_t*>(chars.end()));
120 }
121
122 uint8_t* ValueSerializer::ReserveRawBytes(size_t bytes) {
123 auto old_size = buffer_.size();
124 buffer_.resize(buffer_.size() + bytes);
125 return &buffer_[old_size];
126 }
127
95 Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) { 128 Maybe<bool> ValueSerializer::WriteObject(Handle<Object> object) {
96 if (object->IsSmi()) { 129 if (object->IsSmi()) {
97 WriteSmi(Smi::cast(*object)); 130 WriteSmi(Smi::cast(*object));
98 return Just(true); 131 return Just(true);
99 } 132 }
100 133
101 DCHECK(object->IsHeapObject()); 134 DCHECK(object->IsHeapObject());
102 switch (HeapObject::cast(*object)->map()->instance_type()) { 135 switch (HeapObject::cast(*object)->map()->instance_type()) {
103 case ODDBALL_TYPE: 136 case ODDBALL_TYPE:
104 WriteOddball(Oddball::cast(*object)); 137 WriteOddball(Oddball::cast(*object));
105 return Just(true); 138 return Just(true);
106 case HEAP_NUMBER_TYPE: 139 case HEAP_NUMBER_TYPE:
107 case MUTABLE_HEAP_NUMBER_TYPE: 140 case MUTABLE_HEAP_NUMBER_TYPE:
108 WriteHeapNumber(HeapNumber::cast(*object)); 141 WriteHeapNumber(HeapNumber::cast(*object));
109 return Just(true); 142 return Just(true);
110 default: 143 default:
144 if (object->IsString()) {
145 WriteString(Handle<String>::cast(object));
146 return Just(true);
147 }
111 UNIMPLEMENTED(); 148 UNIMPLEMENTED();
112 return Nothing<bool>(); 149 return Nothing<bool>();
113 } 150 }
114 } 151 }
115 152
116 void ValueSerializer::WriteOddball(Oddball* oddball) { 153 void ValueSerializer::WriteOddball(Oddball* oddball) {
117 SerializationTag tag = SerializationTag::kUndefined; 154 SerializationTag tag = SerializationTag::kUndefined;
118 switch (oddball->kind()) { 155 switch (oddball->kind()) {
119 case Oddball::kUndefined: 156 case Oddball::kUndefined:
120 tag = SerializationTag::kUndefined; 157 tag = SerializationTag::kUndefined;
(...skipping 18 matching lines...) Expand all
139 static_assert(kSmiValueSize <= 32, "Expected SMI <= 32 bits."); 176 static_assert(kSmiValueSize <= 32, "Expected SMI <= 32 bits.");
140 WriteTag(SerializationTag::kInt32); 177 WriteTag(SerializationTag::kInt32);
141 WriteZigZag<int32_t>(smi->value()); 178 WriteZigZag<int32_t>(smi->value());
142 } 179 }
143 180
144 void ValueSerializer::WriteHeapNumber(HeapNumber* number) { 181 void ValueSerializer::WriteHeapNumber(HeapNumber* number) {
145 WriteTag(SerializationTag::kDouble); 182 WriteTag(SerializationTag::kDouble);
146 WriteDouble(number->value()); 183 WriteDouble(number->value());
147 } 184 }
148 185
186 void ValueSerializer::WriteString(Handle<String> string) {
187 string = String::Flatten(string);
188 DisallowHeapAllocation no_gc;
189 String::FlatContent flat = string->GetFlatContent();
190 DCHECK(flat.IsFlat());
191 if (flat.IsOneByte()) {
192 // The existing format uses UTF-8, rather than Latin-1. As a result we must
193 // to do work to encode strings that have characters outside ASCII.
194 // TODO(jbroman): In a future format version, consider adding a tag for
195 // Latin-1 strings, so that this can be skipped.
196 WriteTag(SerializationTag::kUtf8String);
197 Vector<const uint8_t> chars = flat.ToOneByteVector();
198 if (String::IsAscii(chars.begin(), chars.length())) {
199 WriteOneByteString(chars);
200 } else {
201 v8::Local<v8::String> api_string = Utils::ToLocal(string);
202 uint32_t utf8_length = api_string->Utf8Length();
203 WriteVarint(utf8_length);
204 api_string->WriteUtf8(
205 reinterpret_cast<char*>(ReserveRawBytes(utf8_length)), utf8_length,
206 nullptr, v8::String::NO_NULL_TERMINATION);
207 }
208 } else if (flat.IsTwoByte()) {
209 Vector<const uc16> chars = flat.ToUC16Vector();
210 uint32_t byte_length = chars.length() * sizeof(uc16);
211 // The existing reading code expects 16-byte strings to be aligned.
212 if ((buffer_.size() + 1 + BytesNeededForVarint(byte_length)) & 1)
213 WriteTag(SerializationTag::kPadding);
214 WriteTag(SerializationTag::kTwoByteString);
215 WriteTwoByteString(chars);
216 } else {
217 UNREACHABLE();
218 }
219 }
220
149 ValueDeserializer::ValueDeserializer(Isolate* isolate, 221 ValueDeserializer::ValueDeserializer(Isolate* isolate,
150 Vector<const uint8_t> data) 222 Vector<const uint8_t> data)
151 : isolate_(isolate), 223 : isolate_(isolate),
152 position_(data.start()), 224 position_(data.start()),
153 end_(data.start() + data.length()) {} 225 end_(data.start() + data.length()) {}
154 226
155 ValueDeserializer::~ValueDeserializer() {} 227 ValueDeserializer::~ValueDeserializer() {}
156 228
157 Maybe<bool> ValueDeserializer::ReadHeader() { 229 Maybe<bool> ValueDeserializer::ReadHeader() {
158 if (position_ < end_ && 230 if (position_ < end_ &&
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
216 Maybe<double> ValueDeserializer::ReadDouble() { 288 Maybe<double> ValueDeserializer::ReadDouble() {
217 // Warning: this uses host endianness. 289 // Warning: this uses host endianness.
218 if (position_ > end_ - sizeof(double)) return Nothing<double>(); 290 if (position_ > end_ - sizeof(double)) return Nothing<double>();
219 double value; 291 double value;
220 memcpy(&value, position_, sizeof(double)); 292 memcpy(&value, position_, sizeof(double));
221 position_ += sizeof(double); 293 position_ += sizeof(double);
222 if (std::isnan(value)) value = std::numeric_limits<double>::quiet_NaN(); 294 if (std::isnan(value)) value = std::numeric_limits<double>::quiet_NaN();
223 return Just(value); 295 return Just(value);
224 } 296 }
225 297
298 Maybe<Vector<const uint8_t>> ValueDeserializer::ReadRawBytes(int size) {
299 if (size > end_ - position_) return Nothing<Vector<const uint8_t>>();
300 const uint8_t* start = position_;
301 position_ += size;
302 return Just(Vector<const uint8_t>(start, size));
303 }
304
226 MaybeHandle<Object> ValueDeserializer::ReadObject() { 305 MaybeHandle<Object> ValueDeserializer::ReadObject() {
227 SerializationTag tag; 306 SerializationTag tag;
228 if (!ReadTag().To(&tag)) return MaybeHandle<Object>(); 307 if (!ReadTag().To(&tag)) return MaybeHandle<Object>();
229 switch (tag) { 308 switch (tag) {
230 case SerializationTag::kVerifyObjectCount: 309 case SerializationTag::kVerifyObjectCount:
231 // Read the count and ignore it. 310 // Read the count and ignore it.
232 if (ReadVarint<uint32_t>().IsNothing()) return MaybeHandle<Object>(); 311 if (ReadVarint<uint32_t>().IsNothing()) return MaybeHandle<Object>();
233 return ReadObject(); 312 return ReadObject();
234 case SerializationTag::kUndefined: 313 case SerializationTag::kUndefined:
235 return isolate_->factory()->undefined_value(); 314 return isolate_->factory()->undefined_value();
(...skipping 11 matching lines...) Expand all
247 case SerializationTag::kUint32: { 326 case SerializationTag::kUint32: {
248 Maybe<uint32_t> number = ReadVarint<uint32_t>(); 327 Maybe<uint32_t> number = ReadVarint<uint32_t>();
249 if (number.IsNothing()) return MaybeHandle<Object>(); 328 if (number.IsNothing()) return MaybeHandle<Object>();
250 return isolate_->factory()->NewNumberFromUint(number.FromJust()); 329 return isolate_->factory()->NewNumberFromUint(number.FromJust());
251 } 330 }
252 case SerializationTag::kDouble: { 331 case SerializationTag::kDouble: {
253 Maybe<double> number = ReadDouble(); 332 Maybe<double> number = ReadDouble();
254 if (number.IsNothing()) return MaybeHandle<Object>(); 333 if (number.IsNothing()) return MaybeHandle<Object>();
255 return isolate_->factory()->NewNumber(number.FromJust()); 334 return isolate_->factory()->NewNumber(number.FromJust());
256 } 335 }
336 case SerializationTag::kUtf8String:
337 return ReadUtf8String();
338 case SerializationTag::kTwoByteString:
339 return ReadTwoByteString();
257 default: 340 default:
258 return MaybeHandle<Object>(); 341 return MaybeHandle<Object>();
259 } 342 }
260 } 343 }
261 344
345 MaybeHandle<String> ValueDeserializer::ReadUtf8String() {
346 uint32_t utf8_length;
347 Vector<const uint8_t> utf8_bytes;
348 if (!ReadVarint<uint32_t>().To(&utf8_length) ||
349 utf8_length >
350 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
351 !ReadRawBytes(utf8_length).To(&utf8_bytes))
352 return MaybeHandle<String>();
353 return isolate_->factory()->NewStringFromUtf8(
354 Vector<const char>::cast(utf8_bytes));
355 }
356
357 MaybeHandle<String> ValueDeserializer::ReadTwoByteString() {
358 uint32_t byte_length;
359 Vector<const uint8_t> bytes;
360 if (!ReadVarint<uint32_t>().To(&byte_length) ||
361 byte_length >
362 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) ||
363 byte_length % sizeof(uc16) != 0 || !ReadRawBytes(byte_length).To(&bytes))
364 return MaybeHandle<String>();
365
366 // Allocate an uninitialized string so that we can do a raw memcpy into the
367 // string on the heap (regardless of alignment).
368 Handle<SeqTwoByteString> string;
369 if (!isolate_->factory()
370 ->NewRawTwoByteString(byte_length / sizeof(uc16))
371 .ToHandle(&string))
372 return MaybeHandle<String>();
373
374 // Copy the bytes directly into the new string.
375 // Warning: this uses host endianness.
376 memcpy(string->GetChars(), bytes.begin(), bytes.length());
377 return string;
378 }
379
262 } // namespace internal 380 } // namespace internal
263 } // namespace v8 381 } // namespace v8
OLDNEW
« 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