| 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 <algorithm> | 7 #include <algorithm> |
| 8 #include <string> | 8 #include <string> |
| 9 | 9 |
| 10 #include "include/v8.h" | 10 #include "include/v8.h" |
| (...skipping 689 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 700 DecodeTestForVersion0( | 700 DecodeTestForVersion0( |
| 701 {0x49, 0x54, 0x53, 0x01, 0x61, 0x53, 0x01, 0x61, 0x49, 0x54, 0x7b, 0x02}, | 701 {0x49, 0x54, 0x53, 0x01, 0x61, 0x53, 0x01, 0x61, 0x49, 0x54, 0x7b, 0x02}, |
| 702 [this](Local<Value> value) { | 702 [this](Local<Value> value) { |
| 703 EXPECT_TRUE(EvaluateScriptForResultBool( | 703 EXPECT_TRUE(EvaluateScriptForResultBool( |
| 704 "Object.getOwnPropertyNames(result).toString() === '42,a'")); | 704 "Object.getOwnPropertyNames(result).toString() === '42,a'")); |
| 705 EXPECT_TRUE(EvaluateScriptForResultBool("result[42] === 'a'")); | 705 EXPECT_TRUE(EvaluateScriptForResultBool("result[42] === 'a'")); |
| 706 EXPECT_TRUE(EvaluateScriptForResultBool("result.a === 42")); | 706 EXPECT_TRUE(EvaluateScriptForResultBool("result.a === 42")); |
| 707 }); | 707 }); |
| 708 } | 708 } |
| 709 | 709 |
| 710 TEST_F(ValueSerializerTest, RoundTripArray) { | |
| 711 // A simple array of integers. | |
| 712 RoundTripTest("[1, 2, 3, 4, 5]", [this](Local<Value> value) { | |
| 713 ASSERT_TRUE(value->IsArray()); | |
| 714 EXPECT_EQ(5, Array::Cast(*value)->Length()); | |
| 715 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 716 "Object.getPrototypeOf(result) === Array.prototype")); | |
| 717 EXPECT_TRUE( | |
| 718 EvaluateScriptForResultBool("result.toString() === '1,2,3,4,5'")); | |
| 719 }); | |
| 720 // A long (sparse) array. | |
| 721 RoundTripTest( | |
| 722 "(() => { var x = new Array(1000); x[500] = 42; return x; })()", | |
| 723 [this](Local<Value> value) { | |
| 724 ASSERT_TRUE(value->IsArray()); | |
| 725 EXPECT_EQ(1000, Array::Cast(*value)->Length()); | |
| 726 EXPECT_TRUE(EvaluateScriptForResultBool("result[500] === 42")); | |
| 727 }); | |
| 728 // Duplicate reference. | |
| 729 RoundTripTest( | |
| 730 "(() => { var y = {}; return [y, y]; })()", [this](Local<Value> value) { | |
| 731 ASSERT_TRUE(value->IsArray()); | |
| 732 ASSERT_EQ(2, Array::Cast(*value)->Length()); | |
| 733 EXPECT_TRUE(EvaluateScriptForResultBool("result[0] === result[1]")); | |
| 734 }); | |
| 735 // Duplicate reference in a sparse array. | |
| 736 RoundTripTest( | |
| 737 "(() => { var x = new Array(1000); x[1] = x[500] = {}; return x; })()", | |
| 738 [this](Local<Value> value) { | |
| 739 ASSERT_TRUE(value->IsArray()); | |
| 740 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 741 EXPECT_TRUE( | |
| 742 EvaluateScriptForResultBool("typeof result[1] === 'object'")); | |
| 743 EXPECT_TRUE(EvaluateScriptForResultBool("result[1] === result[500]")); | |
| 744 }); | |
| 745 // Self reference. | |
| 746 RoundTripTest( | |
| 747 "(() => { var y = []; y[0] = y; return y; })()", | |
| 748 [this](Local<Value> value) { | |
| 749 ASSERT_TRUE(value->IsArray()); | |
| 750 ASSERT_EQ(1, Array::Cast(*value)->Length()); | |
| 751 EXPECT_TRUE(EvaluateScriptForResultBool("result[0] === result")); | |
| 752 }); | |
| 753 // Self reference in a sparse array. | |
| 754 RoundTripTest( | |
| 755 "(() => { var y = new Array(1000); y[519] = y; return y; })()", | |
| 756 [this](Local<Value> value) { | |
| 757 ASSERT_TRUE(value->IsArray()); | |
| 758 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 759 EXPECT_TRUE(EvaluateScriptForResultBool("result[519] === result")); | |
| 760 }); | |
| 761 // Array with additional properties. | |
| 762 RoundTripTest( | |
| 763 "(() => { var y = [1, 2]; y.foo = 'bar'; return y; })()", | |
| 764 [this](Local<Value> value) { | |
| 765 ASSERT_TRUE(value->IsArray()); | |
| 766 ASSERT_EQ(2, Array::Cast(*value)->Length()); | |
| 767 EXPECT_TRUE(EvaluateScriptForResultBool("result.toString() === '1,2'")); | |
| 768 EXPECT_TRUE(EvaluateScriptForResultBool("result.foo === 'bar'")); | |
| 769 }); | |
| 770 // Sparse array with additional properties. | |
| 771 RoundTripTest( | |
| 772 "(() => { var y = new Array(1000); y.foo = 'bar'; return y; })()", | |
| 773 [this](Local<Value> value) { | |
| 774 ASSERT_TRUE(value->IsArray()); | |
| 775 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 776 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 777 "result.toString() === ','.repeat(999)")); | |
| 778 EXPECT_TRUE(EvaluateScriptForResultBool("result.foo === 'bar'")); | |
| 779 }); | |
| 780 // The distinction between holes and undefined elements must be maintained. | |
| 781 RoundTripTest("[,undefined]", [this](Local<Value> value) { | |
| 782 ASSERT_TRUE(value->IsArray()); | |
| 783 ASSERT_EQ(2, Array::Cast(*value)->Length()); | |
| 784 EXPECT_TRUE( | |
| 785 EvaluateScriptForResultBool("typeof result[0] === 'undefined'")); | |
| 786 EXPECT_TRUE( | |
| 787 EvaluateScriptForResultBool("typeof result[1] === 'undefined'")); | |
| 788 EXPECT_TRUE(EvaluateScriptForResultBool("!result.hasOwnProperty(0)")); | |
| 789 EXPECT_TRUE(EvaluateScriptForResultBool("result.hasOwnProperty(1)")); | |
| 790 }); | |
| 791 } | |
| 792 | |
| 793 TEST_F(ValueSerializerTest, DecodeArray) { | |
| 794 // A simple array of integers. | |
| 795 DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x41, 0x05, 0x3f, 0x01, 0x49, 0x02, | |
| 796 0x3f, 0x01, 0x49, 0x04, 0x3f, 0x01, 0x49, 0x06, 0x3f, 0x01, | |
| 797 0x49, 0x08, 0x3f, 0x01, 0x49, 0x0a, 0x24, 0x00, 0x05, 0x00}, | |
| 798 [this](Local<Value> value) { | |
| 799 ASSERT_TRUE(value->IsArray()); | |
| 800 EXPECT_EQ(5, Array::Cast(*value)->Length()); | |
| 801 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 802 "Object.getPrototypeOf(result) === Array.prototype")); | |
| 803 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 804 "result.toString() === '1,2,3,4,5'")); | |
| 805 }); | |
| 806 // A long (sparse) array. | |
| 807 DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x61, 0xe8, 0x07, 0x3f, 0x01, 0x49, | |
| 808 0xe8, 0x07, 0x3f, 0x01, 0x49, 0x54, 0x40, 0x01, 0xe8, 0x07}, | |
| 809 [this](Local<Value> value) { | |
| 810 ASSERT_TRUE(value->IsArray()); | |
| 811 EXPECT_EQ(1000, Array::Cast(*value)->Length()); | |
| 812 EXPECT_TRUE(EvaluateScriptForResultBool("result[500] === 42")); | |
| 813 }); | |
| 814 // Duplicate reference. | |
| 815 DecodeTest( | |
| 816 {0xff, 0x09, 0x3f, 0x00, 0x41, 0x02, 0x3f, 0x01, 0x6f, 0x7b, 0x00, 0x3f, | |
| 817 0x02, 0x5e, 0x01, 0x24, 0x00, 0x02}, | |
| 818 [this](Local<Value> value) { | |
| 819 ASSERT_TRUE(value->IsArray()); | |
| 820 ASSERT_EQ(2, Array::Cast(*value)->Length()); | |
| 821 EXPECT_TRUE(EvaluateScriptForResultBool("result[0] === result[1]")); | |
| 822 }); | |
| 823 // Duplicate reference in a sparse array. | |
| 824 DecodeTest( | |
| 825 {0xff, 0x09, 0x3f, 0x00, 0x61, 0xe8, 0x07, 0x3f, 0x01, 0x49, | |
| 826 0x02, 0x3f, 0x01, 0x6f, 0x7b, 0x00, 0x3f, 0x02, 0x49, 0xe8, | |
| 827 0x07, 0x3f, 0x02, 0x5e, 0x01, 0x40, 0x02, 0xe8, 0x07, 0x00}, | |
| 828 [this](Local<Value> value) { | |
| 829 ASSERT_TRUE(value->IsArray()); | |
| 830 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 831 EXPECT_TRUE( | |
| 832 EvaluateScriptForResultBool("typeof result[1] === 'object'")); | |
| 833 EXPECT_TRUE(EvaluateScriptForResultBool("result[1] === result[500]")); | |
| 834 }); | |
| 835 // Self reference. | |
| 836 DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x41, 0x01, 0x3f, 0x01, 0x5e, 0x00, 0x24, | |
| 837 0x00, 0x01, 0x00}, | |
| 838 [this](Local<Value> value) { | |
| 839 ASSERT_TRUE(value->IsArray()); | |
| 840 ASSERT_EQ(1, Array::Cast(*value)->Length()); | |
| 841 EXPECT_TRUE(EvaluateScriptForResultBool("result[0] === result")); | |
| 842 }); | |
| 843 // Self reference in a sparse array. | |
| 844 DecodeTest( | |
| 845 {0xff, 0x09, 0x3f, 0x00, 0x61, 0xe8, 0x07, 0x3f, 0x01, 0x49, | |
| 846 0x8e, 0x08, 0x3f, 0x01, 0x5e, 0x00, 0x40, 0x01, 0xe8, 0x07}, | |
| 847 [this](Local<Value> value) { | |
| 848 ASSERT_TRUE(value->IsArray()); | |
| 849 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 850 EXPECT_TRUE(EvaluateScriptForResultBool("result[519] === result")); | |
| 851 }); | |
| 852 // Array with additional properties. | |
| 853 DecodeTest( | |
| 854 {0xff, 0x09, 0x3f, 0x00, 0x41, 0x02, 0x3f, 0x01, 0x49, 0x02, 0x3f, | |
| 855 0x01, 0x49, 0x04, 0x3f, 0x01, 0x53, 0x03, 0x66, 0x6f, 0x6f, 0x3f, | |
| 856 0x01, 0x53, 0x03, 0x62, 0x61, 0x72, 0x24, 0x01, 0x02, 0x00}, | |
| 857 [this](Local<Value> value) { | |
| 858 ASSERT_TRUE(value->IsArray()); | |
| 859 ASSERT_EQ(2, Array::Cast(*value)->Length()); | |
| 860 EXPECT_TRUE(EvaluateScriptForResultBool("result.toString() === '1,2'")); | |
| 861 EXPECT_TRUE(EvaluateScriptForResultBool("result.foo === 'bar'")); | |
| 862 }); | |
| 863 // Sparse array with additional properties. | |
| 864 DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x61, 0xe8, 0x07, 0x3f, 0x01, | |
| 865 0x53, 0x03, 0x66, 0x6f, 0x6f, 0x3f, 0x01, 0x53, 0x03, | |
| 866 0x62, 0x61, 0x72, 0x40, 0x01, 0xe8, 0x07, 0x00}, | |
| 867 [this](Local<Value> value) { | |
| 868 ASSERT_TRUE(value->IsArray()); | |
| 869 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 870 EXPECT_TRUE(EvaluateScriptForResultBool( | |
| 871 "result.toString() === ','.repeat(999)")); | |
| 872 EXPECT_TRUE(EvaluateScriptForResultBool("result.foo === 'bar'")); | |
| 873 }); | |
| 874 // The distinction between holes and undefined elements must be maintained. | |
| 875 // Note that since the previous output from Chrome fails this test, an | |
| 876 // encoding using the sparse format was constructed instead. | |
| 877 DecodeTest( | |
| 878 {0xff, 0x09, 0x61, 0x02, 0x49, 0x02, 0x5f, 0x40, 0x01, 0x02}, | |
| 879 [this](Local<Value> value) { | |
| 880 ASSERT_TRUE(value->IsArray()); | |
| 881 ASSERT_EQ(2, Array::Cast(*value)->Length()); | |
| 882 EXPECT_TRUE( | |
| 883 EvaluateScriptForResultBool("typeof result[0] === 'undefined'")); | |
| 884 EXPECT_TRUE( | |
| 885 EvaluateScriptForResultBool("typeof result[1] === 'undefined'")); | |
| 886 EXPECT_TRUE(EvaluateScriptForResultBool("!result.hasOwnProperty(0)")); | |
| 887 EXPECT_TRUE(EvaluateScriptForResultBool("result.hasOwnProperty(1)")); | |
| 888 }); | |
| 889 } | |
| 890 | |
| 891 TEST_F(ValueSerializerTest, RoundTripArrayWithNonEnumerableElement) { | |
| 892 // Even though this array looks like [1,5,3], the 5 should be missing from the | |
| 893 // perspective of structured clone, which only clones properties that were | |
| 894 // enumerable. | |
| 895 RoundTripTest( | |
| 896 "(() => {" | |
| 897 " var x = [1,2,3];" | |
| 898 " Object.defineProperty(x, '1', {enumerable:false, value:5});" | |
| 899 " return x;" | |
| 900 "})()", | |
| 901 [this](Local<Value> value) { | |
| 902 ASSERT_TRUE(value->IsArray()); | |
| 903 ASSERT_EQ(3, Array::Cast(*value)->Length()); | |
| 904 EXPECT_TRUE(EvaluateScriptForResultBool("!result.hasOwnProperty('1')")); | |
| 905 }); | |
| 906 } | |
| 907 | |
| 908 TEST_F(ValueSerializerTest, RoundTripArrayWithTrickyGetters) { | |
| 909 // If an element is deleted before it is serialized, then it's deleted. | |
| 910 RoundTripTest( | |
| 911 "(() => {" | |
| 912 " var x = [{ get a() { delete x[1]; }}, 42];" | |
| 913 " return x;" | |
| 914 "})()", | |
| 915 [this](Local<Value> value) { | |
| 916 ASSERT_TRUE(value->IsArray()); | |
| 917 ASSERT_EQ(2, Array::Cast(*value)->Length()); | |
| 918 EXPECT_TRUE( | |
| 919 EvaluateScriptForResultBool("typeof result[1] === 'undefined'")); | |
| 920 EXPECT_TRUE(EvaluateScriptForResultBool("!result.hasOwnProperty(1)")); | |
| 921 }); | |
| 922 // Same for sparse arrays. | |
| 923 RoundTripTest( | |
| 924 "(() => {" | |
| 925 " var x = [{ get a() { delete x[1]; }}, 42];" | |
| 926 " x.length = 1000;" | |
| 927 " return x;" | |
| 928 "})()", | |
| 929 [this](Local<Value> value) { | |
| 930 ASSERT_TRUE(value->IsArray()); | |
| 931 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 932 EXPECT_TRUE( | |
| 933 EvaluateScriptForResultBool("typeof result[1] === 'undefined'")); | |
| 934 EXPECT_TRUE(EvaluateScriptForResultBool("!result.hasOwnProperty(1)")); | |
| 935 }); | |
| 936 // If the length is changed, then the resulting array still has the original | |
| 937 // length, but elements that were not yet serialized are gone. | |
| 938 RoundTripTest( | |
| 939 "(() => {" | |
| 940 " var x = [1, { get a() { x.length = 0; }}, 3, 4];" | |
| 941 " return x;" | |
| 942 "})()", | |
| 943 [this](Local<Value> value) { | |
| 944 ASSERT_TRUE(value->IsArray()); | |
| 945 ASSERT_EQ(4, Array::Cast(*value)->Length()); | |
| 946 EXPECT_TRUE(EvaluateScriptForResultBool("result[0] === 1")); | |
| 947 EXPECT_TRUE(EvaluateScriptForResultBool("!result.hasOwnProperty(2)")); | |
| 948 }); | |
| 949 // Same for sparse arrays. | |
| 950 RoundTripTest( | |
| 951 "(() => {" | |
| 952 " var x = [1, { get a() { x.length = 0; }}, 3, 4];" | |
| 953 " x.length = 1000;" | |
| 954 " return x;" | |
| 955 "})()", | |
| 956 [this](Local<Value> value) { | |
| 957 ASSERT_TRUE(value->IsArray()); | |
| 958 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 959 EXPECT_TRUE(EvaluateScriptForResultBool("result[0] === 1")); | |
| 960 EXPECT_TRUE(EvaluateScriptForResultBool("!result.hasOwnProperty(2)")); | |
| 961 }); | |
| 962 // If a getter makes a property non-enumerable, it should still be enumerated | |
| 963 // as enumeration happens once before getters are invoked. | |
| 964 RoundTripTest( | |
| 965 "(() => {" | |
| 966 " var x = [{ get a() {" | |
| 967 " Object.defineProperty(x, '1', { value: 3, enumerable: false });" | |
| 968 " }}, 2];" | |
| 969 " return x;" | |
| 970 "})()", | |
| 971 [this](Local<Value> value) { | |
| 972 ASSERT_TRUE(value->IsArray()); | |
| 973 ASSERT_EQ(2, Array::Cast(*value)->Length()); | |
| 974 EXPECT_TRUE(EvaluateScriptForResultBool("result[1] === 3")); | |
| 975 }); | |
| 976 // Same for sparse arrays. | |
| 977 RoundTripTest( | |
| 978 "(() => {" | |
| 979 " var x = [{ get a() {" | |
| 980 " Object.defineProperty(x, '1', { value: 3, enumerable: false });" | |
| 981 " }}, 2];" | |
| 982 " x.length = 1000;" | |
| 983 " return x;" | |
| 984 "})()", | |
| 985 [this](Local<Value> value) { | |
| 986 ASSERT_TRUE(value->IsArray()); | |
| 987 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 988 EXPECT_TRUE(EvaluateScriptForResultBool("result[1] === 3")); | |
| 989 }); | |
| 990 // Getters on the array itself must also run. | |
| 991 RoundTripTest( | |
| 992 "(() => {" | |
| 993 " var x = [1, 2, 3];" | |
| 994 " Object.defineProperty(x, '1', { enumerable: true, get: () => 4 });" | |
| 995 " return x;" | |
| 996 "})()", | |
| 997 [this](Local<Value> value) { | |
| 998 ASSERT_TRUE(value->IsArray()); | |
| 999 ASSERT_EQ(3, Array::Cast(*value)->Length()); | |
| 1000 EXPECT_TRUE(EvaluateScriptForResultBool("result[1] === 4")); | |
| 1001 }); | |
| 1002 // Same for sparse arrays. | |
| 1003 RoundTripTest( | |
| 1004 "(() => {" | |
| 1005 " var x = [1, 2, 3];" | |
| 1006 " Object.defineProperty(x, '1', { enumerable: true, get: () => 4 });" | |
| 1007 " x.length = 1000;" | |
| 1008 " return x;" | |
| 1009 "})()", | |
| 1010 [this](Local<Value> value) { | |
| 1011 ASSERT_TRUE(value->IsArray()); | |
| 1012 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 1013 EXPECT_TRUE(EvaluateScriptForResultBool("result[1] === 4")); | |
| 1014 }); | |
| 1015 // Even with a getter that deletes things, we don't read from the prototype. | |
| 1016 RoundTripTest( | |
| 1017 "(() => {" | |
| 1018 " var x = [{ get a() { delete x[1]; } }, 2];" | |
| 1019 " x.__proto__ = Object.create(Array.prototype, { 1: { value: 6 } });" | |
| 1020 " return x;" | |
| 1021 "})()", | |
| 1022 [this](Local<Value> value) { | |
| 1023 ASSERT_TRUE(value->IsArray()); | |
| 1024 ASSERT_EQ(2, Array::Cast(*value)->Length()); | |
| 1025 EXPECT_TRUE(EvaluateScriptForResultBool("!(1 in result)")); | |
| 1026 }); | |
| 1027 // Same for sparse arrays. | |
| 1028 RoundTripTest( | |
| 1029 "(() => {" | |
| 1030 " var x = [{ get a() { delete x[1]; } }, 2];" | |
| 1031 " x.__proto__ = Object.create(Array.prototype, { 1: { value: 6 } });" | |
| 1032 " x.length = 1000;" | |
| 1033 " return x;" | |
| 1034 "})()", | |
| 1035 [this](Local<Value> value) { | |
| 1036 ASSERT_TRUE(value->IsArray()); | |
| 1037 ASSERT_EQ(1000, Array::Cast(*value)->Length()); | |
| 1038 EXPECT_TRUE(EvaluateScriptForResultBool("!(1 in result)")); | |
| 1039 }); | |
| 1040 } | |
| 1041 | |
| 1042 } // namespace | 710 } // namespace |
| 1043 } // namespace v8 | 711 } // namespace v8 |
| OLD | NEW |