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(); | |
Camillo Bruni
2016/08/14 15:10:48
performance nit: I'd prefer not wrapping the Handl
jbroman
2016/08/15 01:33:52
Agreed that wrapping in a Local<> isn't great. Ide
| |
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 > std::numeric_limits<int>::max() || | |
350 !ReadRawBytes(utf8_length).To(&utf8_bytes)) | |
351 return MaybeHandle<String>(); | |
352 return isolate_->factory()->NewStringFromUtf8( | |
353 Vector<const char>::cast(utf8_bytes)); | |
354 } | |
355 | |
356 MaybeHandle<String> ValueDeserializer::ReadTwoByteString() { | |
357 uint32_t byte_length; | |
358 Vector<const uint8_t> bytes; | |
359 if (!ReadVarint<uint32_t>().To(&byte_length) || | |
360 byte_length > std::numeric_limits<int>::max() || | |
361 byte_length % sizeof(uc16) != 0 || !ReadRawBytes(byte_length).To(&bytes)) | |
362 return MaybeHandle<String>(); | |
363 | |
364 // Allocate an uninitialized string so that we can do a raw memcpy into the | |
365 // string on the heap (regardless of alignment). | |
366 Handle<SeqTwoByteString> string; | |
367 if (!isolate_->factory() | |
368 ->NewRawTwoByteString(byte_length / sizeof(uc16)) | |
369 .ToHandle(&string)) | |
370 return MaybeHandle<String>(); | |
371 | |
372 // Copy the bytes directly into the new string. | |
373 // Warning: this uses host endianness. | |
374 memcpy(string->GetChars(), bytes.begin(), bytes.length()); | |
375 return string; | |
376 } | |
377 | |
262 } // namespace internal | 378 } // namespace internal |
263 } // namespace v8 | 379 } // namespace v8 |
OLD | NEW |