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" |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 // Boolean object. No data. | 75 // Boolean object. No data. |
76 kTrueObject = 'y', | 76 kTrueObject = 'y', |
77 kFalseObject = 'x', | 77 kFalseObject = 'x', |
78 // Number object. value:double | 78 // Number object. value:double |
79 kNumberObject = 'n', | 79 kNumberObject = 'n', |
80 // String object, UTF-8 encoding. byteLength:uint32_t, then raw data. | 80 // String object, UTF-8 encoding. byteLength:uint32_t, then raw data. |
81 kStringObject = 's', | 81 kStringObject = 's', |
82 // Regular expression, UTF-8 encoding. byteLength:uint32_t, raw data, | 82 // Regular expression, UTF-8 encoding. byteLength:uint32_t, raw data, |
83 // flags:uint32_t. | 83 // flags:uint32_t. |
84 kRegExp = 'R', | 84 kRegExp = 'R', |
| 85 // Beginning of a JS map. |
| 86 kBeginJSMap = ';', |
| 87 // End of a JS map. length:uint32_t. |
| 88 kEndJSMap = ':', |
| 89 // Beginning of a JS set. |
| 90 kBeginJSSet = '\'', |
| 91 // End of a JS set. length:uint32_t. |
| 92 kEndJSSet = ',', |
85 }; | 93 }; |
86 | 94 |
87 ValueSerializer::ValueSerializer(Isolate* isolate) | 95 ValueSerializer::ValueSerializer(Isolate* isolate) |
88 : isolate_(isolate), | 96 : isolate_(isolate), |
89 zone_(isolate->allocator()), | 97 zone_(isolate->allocator()), |
90 id_map_(isolate->heap(), &zone_) {} | 98 id_map_(isolate->heap(), &zone_) {} |
91 | 99 |
92 ValueSerializer::~ValueSerializer() {} | 100 ValueSerializer::~ValueSerializer() {} |
93 | 101 |
94 void ValueSerializer::WriteHeader() { | 102 void ValueSerializer::WriteHeader() { |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
282 case JS_API_OBJECT_TYPE: | 290 case JS_API_OBJECT_TYPE: |
283 return WriteJSObject(Handle<JSObject>::cast(receiver)); | 291 return WriteJSObject(Handle<JSObject>::cast(receiver)); |
284 case JS_DATE_TYPE: | 292 case JS_DATE_TYPE: |
285 WriteJSDate(JSDate::cast(*receiver)); | 293 WriteJSDate(JSDate::cast(*receiver)); |
286 return Just(true); | 294 return Just(true); |
287 case JS_VALUE_TYPE: | 295 case JS_VALUE_TYPE: |
288 return WriteJSValue(Handle<JSValue>::cast(receiver)); | 296 return WriteJSValue(Handle<JSValue>::cast(receiver)); |
289 case JS_REGEXP_TYPE: | 297 case JS_REGEXP_TYPE: |
290 WriteJSRegExp(JSRegExp::cast(*receiver)); | 298 WriteJSRegExp(JSRegExp::cast(*receiver)); |
291 return Just(true); | 299 return Just(true); |
| 300 case JS_MAP_TYPE: |
| 301 return WriteJSMap(Handle<JSMap>::cast(receiver)); |
| 302 case JS_SET_TYPE: |
| 303 return WriteJSSet(Handle<JSSet>::cast(receiver)); |
292 default: | 304 default: |
293 UNIMPLEMENTED(); | 305 UNIMPLEMENTED(); |
294 break; | 306 break; |
295 } | 307 } |
296 return Nothing<bool>(); | 308 return Nothing<bool>(); |
297 } | 309 } |
298 | 310 |
299 Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) { | 311 Maybe<bool> ValueSerializer::WriteJSObject(Handle<JSObject> object) { |
300 WriteTag(SerializationTag::kBeginJSObject); | 312 WriteTag(SerializationTag::kBeginJSObject); |
301 Handle<FixedArray> keys; | 313 Handle<FixedArray> keys; |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
410 WriteTag(SerializationTag::kRegExp); | 422 WriteTag(SerializationTag::kRegExp); |
411 v8::Local<v8::String> api_string = | 423 v8::Local<v8::String> api_string = |
412 Utils::ToLocal(handle(regexp->Pattern(), isolate_)); | 424 Utils::ToLocal(handle(regexp->Pattern(), isolate_)); |
413 uint32_t utf8_length = api_string->Utf8Length(); | 425 uint32_t utf8_length = api_string->Utf8Length(); |
414 WriteVarint(utf8_length); | 426 WriteVarint(utf8_length); |
415 api_string->WriteUtf8(reinterpret_cast<char*>(ReserveRawBytes(utf8_length)), | 427 api_string->WriteUtf8(reinterpret_cast<char*>(ReserveRawBytes(utf8_length)), |
416 utf8_length, nullptr, v8::String::NO_NULL_TERMINATION); | 428 utf8_length, nullptr, v8::String::NO_NULL_TERMINATION); |
417 WriteVarint(static_cast<uint32_t>(regexp->GetFlags())); | 429 WriteVarint(static_cast<uint32_t>(regexp->GetFlags())); |
418 } | 430 } |
419 | 431 |
| 432 Maybe<bool> ValueSerializer::WriteJSMap(Handle<JSMap> map) { |
| 433 // First copy the key-value pairs, since getters could mutate them. |
| 434 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table())); |
| 435 int length = table->NumberOfElements() * 2; |
| 436 Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length); |
| 437 { |
| 438 DisallowHeapAllocation no_gc; |
| 439 Oddball* the_hole = isolate_->heap()->the_hole_value(); |
| 440 int capacity = table->UsedCapacity(); |
| 441 int result_index = 0; |
| 442 for (int i = 0; i < capacity; i++) { |
| 443 Object* key = table->KeyAt(i); |
| 444 if (key == the_hole) continue; |
| 445 entries->set(result_index++, key); |
| 446 entries->set(result_index++, table->ValueAt(i)); |
| 447 } |
| 448 DCHECK_EQ(result_index, length); |
| 449 } |
| 450 |
| 451 // Then write it out. |
| 452 WriteTag(SerializationTag::kBeginJSMap); |
| 453 for (int i = 0; i < length; i++) { |
| 454 if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) { |
| 455 return Nothing<bool>(); |
| 456 } |
| 457 } |
| 458 WriteTag(SerializationTag::kEndJSMap); |
| 459 WriteVarint<uint32_t>(length); |
| 460 return Just(true); |
| 461 } |
| 462 |
| 463 Maybe<bool> ValueSerializer::WriteJSSet(Handle<JSSet> set) { |
| 464 // First copy the element pointers, since getters could mutate them. |
| 465 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table())); |
| 466 int length = table->NumberOfElements(); |
| 467 Handle<FixedArray> entries = isolate_->factory()->NewFixedArray(length); |
| 468 { |
| 469 DisallowHeapAllocation no_gc; |
| 470 Oddball* the_hole = isolate_->heap()->the_hole_value(); |
| 471 int capacity = table->UsedCapacity(); |
| 472 int result_index = 0; |
| 473 for (int i = 0; i < capacity; i++) { |
| 474 Object* key = table->KeyAt(i); |
| 475 if (key == the_hole) continue; |
| 476 entries->set(result_index++, key); |
| 477 } |
| 478 DCHECK_EQ(result_index, length); |
| 479 } |
| 480 |
| 481 // Then write it out. |
| 482 WriteTag(SerializationTag::kBeginJSSet); |
| 483 for (int i = 0; i < length; i++) { |
| 484 if (!WriteObject(handle(entries->get(i), isolate_)).FromMaybe(false)) { |
| 485 return Nothing<bool>(); |
| 486 } |
| 487 } |
| 488 WriteTag(SerializationTag::kEndJSSet); |
| 489 WriteVarint<uint32_t>(length); |
| 490 return Just(true); |
| 491 } |
| 492 |
420 Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties( | 493 Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties( |
421 Handle<JSObject> object, Handle<FixedArray> keys) { | 494 Handle<JSObject> object, Handle<FixedArray> keys) { |
422 uint32_t properties_written = 0; | 495 uint32_t properties_written = 0; |
423 int length = keys->length(); | 496 int length = keys->length(); |
424 for (int i = 0; i < length; i++) { | 497 for (int i = 0; i < length; i++) { |
425 Handle<Object> key(keys->get(i), isolate_); | 498 Handle<Object> key(keys->get(i), isolate_); |
426 | 499 |
427 bool success; | 500 bool success; |
428 LookupIterator it = LookupIterator::PropertyOrElement( | 501 LookupIterator it = LookupIterator::PropertyOrElement( |
429 isolate_, object, key, &success, LookupIterator::OWN); | 502 isolate_, object, key, &success, LookupIterator::OWN); |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
599 return ReadDenseJSArray(); | 672 return ReadDenseJSArray(); |
600 case SerializationTag::kDate: | 673 case SerializationTag::kDate: |
601 return ReadJSDate(); | 674 return ReadJSDate(); |
602 case SerializationTag::kTrueObject: | 675 case SerializationTag::kTrueObject: |
603 case SerializationTag::kFalseObject: | 676 case SerializationTag::kFalseObject: |
604 case SerializationTag::kNumberObject: | 677 case SerializationTag::kNumberObject: |
605 case SerializationTag::kStringObject: | 678 case SerializationTag::kStringObject: |
606 return ReadJSValue(tag); | 679 return ReadJSValue(tag); |
607 case SerializationTag::kRegExp: | 680 case SerializationTag::kRegExp: |
608 return ReadJSRegExp(); | 681 return ReadJSRegExp(); |
| 682 case SerializationTag::kBeginJSMap: |
| 683 return ReadJSMap(); |
| 684 case SerializationTag::kBeginJSSet: |
| 685 return ReadJSSet(); |
609 default: | 686 default: |
610 return MaybeHandle<Object>(); | 687 return MaybeHandle<Object>(); |
611 } | 688 } |
612 } | 689 } |
613 | 690 |
614 MaybeHandle<String> ValueDeserializer::ReadUtf8String() { | 691 MaybeHandle<String> ValueDeserializer::ReadUtf8String() { |
615 uint32_t utf8_length; | 692 uint32_t utf8_length; |
616 Vector<const uint8_t> utf8_bytes; | 693 Vector<const uint8_t> utf8_bytes; |
617 if (!ReadVarint<uint32_t>().To(&utf8_length) || | 694 if (!ReadVarint<uint32_t>().To(&utf8_length) || |
618 utf8_length > | 695 utf8_length > |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
794 if (!ReadUtf8String().ToHandle(&pattern) || | 871 if (!ReadUtf8String().ToHandle(&pattern) || |
795 !ReadVarint<uint32_t>().To(&raw_flags) || | 872 !ReadVarint<uint32_t>().To(&raw_flags) || |
796 !JSRegExp::New(pattern, static_cast<JSRegExp::Flags>(raw_flags)) | 873 !JSRegExp::New(pattern, static_cast<JSRegExp::Flags>(raw_flags)) |
797 .ToHandle(®exp)) { | 874 .ToHandle(®exp)) { |
798 return MaybeHandle<JSRegExp>(); | 875 return MaybeHandle<JSRegExp>(); |
799 } | 876 } |
800 AddObjectWithID(id, regexp); | 877 AddObjectWithID(id, regexp); |
801 return regexp; | 878 return regexp; |
802 } | 879 } |
803 | 880 |
| 881 MaybeHandle<JSMap> ValueDeserializer::ReadJSMap() { |
| 882 // If we are at the end of the stack, abort. This function may recurse. |
| 883 if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSMap>(); |
| 884 |
| 885 HandleScope scope(isolate_); |
| 886 uint32_t id = next_id_++; |
| 887 Handle<JSMap> map = isolate_->factory()->NewJSMap(); |
| 888 AddObjectWithID(id, map); |
| 889 |
| 890 Handle<JSFunction> map_set = isolate_->map_set(); |
| 891 uint32_t length = 0; |
| 892 while (true) { |
| 893 SerializationTag tag; |
| 894 if (!PeekTag().To(&tag)) return MaybeHandle<JSMap>(); |
| 895 if (tag == SerializationTag::kEndJSMap) { |
| 896 ConsumeTag(SerializationTag::kEndJSMap); |
| 897 break; |
| 898 } |
| 899 |
| 900 Handle<Object> argv[2]; |
| 901 if (!ReadObject().ToHandle(&argv[0]) || !ReadObject().ToHandle(&argv[1]) || |
| 902 Execution::Call(isolate_, map_set, map, arraysize(argv), argv) |
| 903 .is_null()) { |
| 904 return MaybeHandle<JSMap>(); |
| 905 } |
| 906 length += 2; |
| 907 } |
| 908 |
| 909 uint32_t expected_length; |
| 910 if (!ReadVarint<uint32_t>().To(&expected_length) || |
| 911 length != expected_length) { |
| 912 return MaybeHandle<JSMap>(); |
| 913 } |
| 914 DCHECK(HasObjectWithID(id)); |
| 915 return scope.CloseAndEscape(map); |
| 916 } |
| 917 |
| 918 MaybeHandle<JSSet> ValueDeserializer::ReadJSSet() { |
| 919 // If we are at the end of the stack, abort. This function may recurse. |
| 920 if (StackLimitCheck(isolate_).HasOverflowed()) return MaybeHandle<JSSet>(); |
| 921 |
| 922 HandleScope scope(isolate_); |
| 923 uint32_t id = next_id_++; |
| 924 Handle<JSSet> set = isolate_->factory()->NewJSSet(); |
| 925 AddObjectWithID(id, set); |
| 926 Handle<JSFunction> set_add = isolate_->set_add(); |
| 927 uint32_t length = 0; |
| 928 while (true) { |
| 929 SerializationTag tag; |
| 930 if (!PeekTag().To(&tag)) return MaybeHandle<JSSet>(); |
| 931 if (tag == SerializationTag::kEndJSSet) { |
| 932 ConsumeTag(SerializationTag::kEndJSSet); |
| 933 break; |
| 934 } |
| 935 |
| 936 Handle<Object> argv[1]; |
| 937 if (!ReadObject().ToHandle(&argv[0]) || |
| 938 Execution::Call(isolate_, set_add, set, arraysize(argv), argv) |
| 939 .is_null()) { |
| 940 return MaybeHandle<JSSet>(); |
| 941 } |
| 942 length++; |
| 943 } |
| 944 |
| 945 uint32_t expected_length; |
| 946 if (!ReadVarint<uint32_t>().To(&expected_length) || |
| 947 length != expected_length) { |
| 948 return MaybeHandle<JSSet>(); |
| 949 } |
| 950 DCHECK(HasObjectWithID(id)); |
| 951 return scope.CloseAndEscape(set); |
| 952 } |
| 953 |
804 Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties( | 954 Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties( |
805 Handle<JSObject> object, SerializationTag end_tag) { | 955 Handle<JSObject> object, SerializationTag end_tag) { |
806 for (uint32_t num_properties = 0;; num_properties++) { | 956 for (uint32_t num_properties = 0;; num_properties++) { |
807 SerializationTag tag; | 957 SerializationTag tag; |
808 if (!PeekTag().To(&tag)) return Nothing<uint32_t>(); | 958 if (!PeekTag().To(&tag)) return Nothing<uint32_t>(); |
809 if (tag == end_tag) { | 959 if (tag == end_tag) { |
810 ConsumeTag(end_tag); | 960 ConsumeTag(end_tag); |
811 return Just(num_properties); | 961 return Just(num_properties); |
812 } | 962 } |
813 | 963 |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
958 } | 1108 } |
959 #endif | 1109 #endif |
960 position_ = end_; | 1110 position_ = end_; |
961 | 1111 |
962 if (stack.size() != 1) return MaybeHandle<Object>(); | 1112 if (stack.size() != 1) return MaybeHandle<Object>(); |
963 return scope.CloseAndEscape(stack[0]); | 1113 return scope.CloseAndEscape(stack[0]); |
964 } | 1114 } |
965 | 1115 |
966 } // namespace internal | 1116 } // namespace internal |
967 } // namespace v8 | 1117 } // namespace v8 |
OLD | NEW |