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/conversions.h" | 10 #include "src/conversions.h" |
11 #include "src/factory.h" | 11 #include "src/factory.h" |
12 #include "src/flags.h" | 12 #include "src/flags.h" |
13 #include "src/handles-inl.h" | 13 #include "src/handles-inl.h" |
14 #include "src/isolate.h" | 14 #include "src/isolate.h" |
15 #include "src/objects-inl.h" | 15 #include "src/objects-inl.h" |
16 #include "src/objects.h" | 16 #include "src/objects.h" |
17 #include "src/snapshot/code-serializer.h" | 17 #include "src/snapshot/code-serializer.h" |
18 #include "src/transitions.h" | 18 #include "src/transitions.h" |
19 #include "src/wasm/wasm-module.h" | 19 #include "src/wasm/wasm-module.h" |
20 #include "src/wasm/wasm-objects.h" | 20 #include "src/wasm/wasm-objects.h" |
21 #include "src/wasm/wasm-result.h" | 21 #include "src/wasm/wasm-result.h" |
22 | 22 |
23 namespace v8 { | 23 namespace v8 { |
24 namespace internal { | 24 namespace internal { |
25 | 25 |
26 static const uint32_t kLatestVersion = 9; | 26 // Version 9: (imported from Blink) |
| 27 // Version 10: one-byte (Latin-1) strings |
| 28 static const uint32_t kLatestVersion = 10; |
| 29 |
27 static const int kPretenureThreshold = 100 * KB; | 30 static const int kPretenureThreshold = 100 * KB; |
28 | 31 |
29 template <typename T> | 32 template <typename T> |
30 static size_t BytesNeededForVarint(T value) { | 33 static size_t BytesNeededForVarint(T value) { |
31 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, | 34 static_assert(std::is_integral<T>::value && std::is_unsigned<T>::value, |
32 "Only unsigned integer types can be written as varints."); | 35 "Only unsigned integer types can be written as varints."); |
33 size_t result = 0; | 36 size_t result = 0; |
34 do { | 37 do { |
35 result++; | 38 result++; |
36 value >>= 7; | 39 value >>= 7; |
(...skipping 17 matching lines...) Expand all Loading... |
54 // (like sint32 in protobuf) | 57 // (like sint32 in protobuf) |
55 kInt32 = 'I', | 58 kInt32 = 'I', |
56 // Number represented as 32-bit unsigned integer, varint-encoded | 59 // Number represented as 32-bit unsigned integer, varint-encoded |
57 // (like uint32 in protobuf) | 60 // (like uint32 in protobuf) |
58 kUint32 = 'U', | 61 kUint32 = 'U', |
59 // Number represented as a 64-bit double. | 62 // Number represented as a 64-bit double. |
60 // Host byte order is used (N.B. this makes the format non-portable). | 63 // Host byte order is used (N.B. this makes the format non-portable). |
61 kDouble = 'N', | 64 kDouble = 'N', |
62 // byteLength:uint32_t, then raw data | 65 // byteLength:uint32_t, then raw data |
63 kUtf8String = 'S', | 66 kUtf8String = 'S', |
| 67 kOneByteString = '"', |
64 kTwoByteString = 'c', | 68 kTwoByteString = 'c', |
65 // Reference to a serialized object. objectID:uint32_t | 69 // Reference to a serialized object. objectID:uint32_t |
66 kObjectReference = '^', | 70 kObjectReference = '^', |
67 // Beginning of a JS object. | 71 // Beginning of a JS object. |
68 kBeginJSObject = 'o', | 72 kBeginJSObject = 'o', |
69 // End of a JS object. numProperties:uint32_t | 73 // End of a JS object. numProperties:uint32_t |
70 kEndJSObject = '{', | 74 kEndJSObject = '{', |
71 // Beginning of a sparse JS array. length:uint32_t | 75 // Beginning of a sparse JS array. length:uint32_t |
72 // Elements and properties are written as key/value pairs, like objects. | 76 // Elements and properties are written as key/value pairs, like objects. |
73 kBeginSparseJSArray = 'a', | 77 kBeginSparseJSArray = 'a', |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
365 WriteTag(SerializationTag::kDouble); | 369 WriteTag(SerializationTag::kDouble); |
366 WriteDouble(number->value()); | 370 WriteDouble(number->value()); |
367 } | 371 } |
368 | 372 |
369 void ValueSerializer::WriteString(Handle<String> string) { | 373 void ValueSerializer::WriteString(Handle<String> string) { |
370 string = String::Flatten(string); | 374 string = String::Flatten(string); |
371 DisallowHeapAllocation no_gc; | 375 DisallowHeapAllocation no_gc; |
372 String::FlatContent flat = string->GetFlatContent(); | 376 String::FlatContent flat = string->GetFlatContent(); |
373 DCHECK(flat.IsFlat()); | 377 DCHECK(flat.IsFlat()); |
374 if (flat.IsOneByte()) { | 378 if (flat.IsOneByte()) { |
375 // The existing format uses UTF-8, rather than Latin-1. As a result we must | |
376 // to do work to encode strings that have characters outside ASCII. | |
377 // TODO(jbroman): In a future format version, consider adding a tag for | |
378 // Latin-1 strings, so that this can be skipped. | |
379 WriteTag(SerializationTag::kUtf8String); | |
380 Vector<const uint8_t> chars = flat.ToOneByteVector(); | 379 Vector<const uint8_t> chars = flat.ToOneByteVector(); |
381 if (String::IsAscii(chars.begin(), chars.length())) { | 380 WriteTag(SerializationTag::kOneByteString); |
382 WriteOneByteString(chars); | 381 WriteOneByteString(chars); |
383 } else { | |
384 v8::Local<v8::String> api_string = Utils::ToLocal(string); | |
385 uint32_t utf8_length = api_string->Utf8Length(); | |
386 WriteVarint(utf8_length); | |
387 uint8_t* dest; | |
388 if (ReserveRawBytes(utf8_length).To(&dest)) { | |
389 api_string->WriteUtf8(reinterpret_cast<char*>(dest), utf8_length, | |
390 nullptr, v8::String::NO_NULL_TERMINATION); | |
391 } | |
392 } | |
393 } else if (flat.IsTwoByte()) { | 382 } else if (flat.IsTwoByte()) { |
394 Vector<const uc16> chars = flat.ToUC16Vector(); | 383 Vector<const uc16> chars = flat.ToUC16Vector(); |
395 uint32_t byte_length = chars.length() * sizeof(uc16); | 384 uint32_t byte_length = chars.length() * sizeof(uc16); |
396 // The existing reading code expects 16-byte strings to be aligned. | 385 // The existing reading code expects 16-byte strings to be aligned. |
397 if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1) | 386 if ((buffer_size_ + 1 + BytesNeededForVarint(byte_length)) & 1) |
398 WriteTag(SerializationTag::kPadding); | 387 WriteTag(SerializationTag::kPadding); |
399 WriteTag(SerializationTag::kTwoByteString); | 388 WriteTag(SerializationTag::kTwoByteString); |
400 WriteTwoByteString(chars); | 389 WriteTwoByteString(chars); |
401 } else { | 390 } else { |
402 UNREACHABLE(); | 391 UNREACHABLE(); |
(...skipping 706 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1109 return isolate_->factory()->NewNumberFromUint(number.FromJust(), | 1098 return isolate_->factory()->NewNumberFromUint(number.FromJust(), |
1110 pretenure_); | 1099 pretenure_); |
1111 } | 1100 } |
1112 case SerializationTag::kDouble: { | 1101 case SerializationTag::kDouble: { |
1113 Maybe<double> number = ReadDouble(); | 1102 Maybe<double> number = ReadDouble(); |
1114 if (number.IsNothing()) return MaybeHandle<Object>(); | 1103 if (number.IsNothing()) return MaybeHandle<Object>(); |
1115 return isolate_->factory()->NewNumber(number.FromJust(), pretenure_); | 1104 return isolate_->factory()->NewNumber(number.FromJust(), pretenure_); |
1116 } | 1105 } |
1117 case SerializationTag::kUtf8String: | 1106 case SerializationTag::kUtf8String: |
1118 return ReadUtf8String(); | 1107 return ReadUtf8String(); |
| 1108 case SerializationTag::kOneByteString: |
| 1109 return ReadOneByteString(); |
1119 case SerializationTag::kTwoByteString: | 1110 case SerializationTag::kTwoByteString: |
1120 return ReadTwoByteString(); | 1111 return ReadTwoByteString(); |
1121 case SerializationTag::kObjectReference: { | 1112 case SerializationTag::kObjectReference: { |
1122 uint32_t id; | 1113 uint32_t id; |
1123 if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>(); | 1114 if (!ReadVarint<uint32_t>().To(&id)) return MaybeHandle<Object>(); |
1124 return GetObjectWithID(id); | 1115 return GetObjectWithID(id); |
1125 } | 1116 } |
1126 case SerializationTag::kBeginJSObject: | 1117 case SerializationTag::kBeginJSObject: |
1127 return ReadJSObject(); | 1118 return ReadJSObject(); |
1128 case SerializationTag::kBeginSparseJSArray: | 1119 case SerializationTag::kBeginSparseJSArray: |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1168 if (!ReadVarint<uint32_t>().To(&utf8_length) || | 1159 if (!ReadVarint<uint32_t>().To(&utf8_length) || |
1169 utf8_length > | 1160 utf8_length > |
1170 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) || | 1161 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) || |
1171 !ReadRawBytes(utf8_length).To(&utf8_bytes)) { | 1162 !ReadRawBytes(utf8_length).To(&utf8_bytes)) { |
1172 return MaybeHandle<String>(); | 1163 return MaybeHandle<String>(); |
1173 } | 1164 } |
1174 return isolate_->factory()->NewStringFromUtf8( | 1165 return isolate_->factory()->NewStringFromUtf8( |
1175 Vector<const char>::cast(utf8_bytes), pretenure_); | 1166 Vector<const char>::cast(utf8_bytes), pretenure_); |
1176 } | 1167 } |
1177 | 1168 |
| 1169 MaybeHandle<String> ValueDeserializer::ReadOneByteString() { |
| 1170 uint32_t byte_length; |
| 1171 Vector<const uint8_t> bytes; |
| 1172 if (!ReadVarint<uint32_t>().To(&byte_length) || |
| 1173 byte_length > |
| 1174 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) || |
| 1175 !ReadRawBytes(byte_length).To(&bytes)) { |
| 1176 return MaybeHandle<String>(); |
| 1177 } |
| 1178 return isolate_->factory()->NewStringFromOneByte(bytes, pretenure_); |
| 1179 } |
| 1180 |
1178 MaybeHandle<String> ValueDeserializer::ReadTwoByteString() { | 1181 MaybeHandle<String> ValueDeserializer::ReadTwoByteString() { |
1179 uint32_t byte_length; | 1182 uint32_t byte_length; |
1180 Vector<const uint8_t> bytes; | 1183 Vector<const uint8_t> bytes; |
1181 if (!ReadVarint<uint32_t>().To(&byte_length) || | 1184 if (!ReadVarint<uint32_t>().To(&byte_length) || |
1182 byte_length > | 1185 byte_length > |
1183 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) || | 1186 static_cast<uint32_t>(std::numeric_limits<int32_t>::max()) || |
1184 byte_length % sizeof(uc16) != 0 || | 1187 byte_length % sizeof(uc16) != 0 || |
1185 !ReadRawBytes(byte_length).To(&bytes)) { | 1188 !ReadRawBytes(byte_length).To(&bytes)) { |
1186 return MaybeHandle<String>(); | 1189 return MaybeHandle<String>(); |
1187 } | 1190 } |
(...skipping 728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1916 if (stack.size() != 1) { | 1919 if (stack.size() != 1) { |
1917 isolate_->Throw(*isolate_->factory()->NewError( | 1920 isolate_->Throw(*isolate_->factory()->NewError( |
1918 MessageTemplate::kDataCloneDeserializationError)); | 1921 MessageTemplate::kDataCloneDeserializationError)); |
1919 return MaybeHandle<Object>(); | 1922 return MaybeHandle<Object>(); |
1920 } | 1923 } |
1921 return scope.CloseAndEscape(stack[0]); | 1924 return scope.CloseAndEscape(stack[0]); |
1922 } | 1925 } |
1923 | 1926 |
1924 } // namespace internal | 1927 } // namespace internal |
1925 } // namespace v8 | 1928 } // namespace v8 |
OLD | NEW |