OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |