OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #include "src/execution.h" | 7 #include "src/execution.h" |
8 #include "src/handles.h" | 8 #include "src/handles.h" |
9 #include "src/interpreter/bytecode-array-builder.h" | 9 #include "src/interpreter/bytecode-array-builder.h" |
10 #include "src/interpreter/interpreter.h" | 10 #include "src/interpreter/interpreter.h" |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 | 144 |
145 DISALLOW_COPY_AND_ASSIGN(InterpreterTester); | 145 DISALLOW_COPY_AND_ASSIGN(InterpreterTester); |
146 }; | 146 }; |
147 | 147 |
148 } // namespace interpreter | 148 } // namespace interpreter |
149 } // namespace internal | 149 } // namespace internal |
150 } // namespace v8 | 150 } // namespace v8 |
151 | 151 |
152 using v8::internal::BytecodeArray; | 152 using v8::internal::BytecodeArray; |
153 using v8::internal::Handle; | 153 using v8::internal::Handle; |
| 154 using v8::internal::LanguageMode; |
154 using v8::internal::Object; | 155 using v8::internal::Object; |
155 using v8::internal::Runtime; | 156 using v8::internal::Runtime; |
156 using v8::internal::Smi; | 157 using v8::internal::Smi; |
157 using v8::internal::Token; | 158 using v8::internal::Token; |
158 using namespace v8::internal::interpreter; | 159 using namespace v8::internal::interpreter; |
159 | 160 |
160 TEST(InterpreterReturn) { | 161 TEST(InterpreterReturn) { |
161 HandleAndZoneScope handles; | 162 HandleAndZoneScope handles; |
162 Handle<Object> undefined_value = | 163 Handle<Object> undefined_value = |
163 handles.main_isolate()->factory()->undefined_value(); | 164 handles.main_isolate()->factory()->undefined_value(); |
(...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
967 .Bind(&done) | 968 .Bind(&done) |
968 .Bind(&done1) | 969 .Bind(&done1) |
969 .Return(); | 970 .Return(); |
970 | 971 |
971 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | 972 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
972 InterpreterTester tester(handles.main_isolate(), bytecode_array); | 973 InterpreterTester tester(handles.main_isolate(), bytecode_array); |
973 auto callable = tester.GetCallable<>(); | 974 auto callable = tester.GetCallable<>(); |
974 Handle<Object> return_value = callable().ToHandleChecked(); | 975 Handle<Object> return_value = callable().ToHandleChecked(); |
975 CHECK_EQ(Smi::cast(*return_value)->value(), 7); | 976 CHECK_EQ(Smi::cast(*return_value)->value(), 7); |
976 } | 977 } |
| 978 |
| 979 |
| 980 static const Token::Value kComparisonTypes[] = { |
| 981 Token::Value::EQ, Token::Value::NE, Token::Value::EQ_STRICT, |
| 982 Token::Value::NE_STRICT, Token::Value::LTE, Token::Value::LTE, |
| 983 Token::Value::GT, Token::Value::GTE}; |
| 984 |
| 985 |
| 986 template <typename T> |
| 987 bool CompareC(Token::Value op, T lhs, T rhs, bool types_differed = false) { |
| 988 switch (op) { |
| 989 case Token::Value::EQ: |
| 990 return lhs == rhs; |
| 991 case Token::Value::NE: |
| 992 return lhs != rhs; |
| 993 case Token::Value::EQ_STRICT: |
| 994 return (lhs == rhs) && !types_differed; |
| 995 case Token::Value::NE_STRICT: |
| 996 return (lhs != rhs) || types_differed; |
| 997 case Token::Value::LT: |
| 998 return lhs < rhs; |
| 999 case Token::Value::LTE: |
| 1000 return lhs <= rhs; |
| 1001 case Token::Value::GT: |
| 1002 return lhs > rhs; |
| 1003 case Token::Value::GTE: |
| 1004 return lhs >= rhs; |
| 1005 default: |
| 1006 UNREACHABLE(); |
| 1007 return false; |
| 1008 } |
| 1009 } |
| 1010 |
| 1011 |
| 1012 TEST(InterpreterSmiComparisons) { |
| 1013 // NB Constants cover 31-bit space. |
| 1014 int inputs[] = {v8::internal::kMinInt / 2, v8::internal::kMinInt / 4, |
| 1015 -108733832, -999, -42, -2, -1, 0, +1, +2, 42, 12345678, |
| 1016 v8::internal::kMaxInt / 4, v8::internal::kMaxInt / 2}; |
| 1017 |
| 1018 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { |
| 1019 Token::Value comparison = kComparisonTypes[c]; |
| 1020 for (size_t i = 0; i < arraysize(inputs); i++) { |
| 1021 for (size_t j = 0; j < arraysize(inputs); j++) { |
| 1022 HandleAndZoneScope handles; |
| 1023 BytecodeArrayBuilder builder(handles.main_isolate(), |
| 1024 handles.main_zone()); |
| 1025 Register r0(0); |
| 1026 builder.set_locals_count(1); |
| 1027 builder.set_parameter_count(0); |
| 1028 builder.LoadLiteral(Smi::FromInt(inputs[i])) |
| 1029 .StoreAccumulatorInRegister(r0) |
| 1030 .LoadLiteral(Smi::FromInt(inputs[j])) |
| 1031 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
| 1032 .Return(); |
| 1033 |
| 1034 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 1035 InterpreterTester tester(handles.main_isolate(), bytecode_array); |
| 1036 auto callable = tester.GetCallable<>(); |
| 1037 Handle<Object> return_value = callable().ToHandleChecked(); |
| 1038 CHECK(return_value->IsBoolean()); |
| 1039 CHECK_EQ(return_value->BooleanValue(), |
| 1040 CompareC(comparison, inputs[i], inputs[j])); |
| 1041 } |
| 1042 } |
| 1043 } |
| 1044 } |
| 1045 |
| 1046 |
| 1047 TEST(InterpreterHeapNumberComparisons) { |
| 1048 double inputs[] = {std::numeric_limits<double>::min(), |
| 1049 std::numeric_limits<double>::max(), |
| 1050 -0.001, 0.01, 0.1000001, 1e99, -1e-99}; |
| 1051 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { |
| 1052 Token::Value comparison = kComparisonTypes[c]; |
| 1053 for (size_t i = 0; i < arraysize(inputs); i++) { |
| 1054 for (size_t j = 0; j < arraysize(inputs); j++) { |
| 1055 HandleAndZoneScope handles; |
| 1056 i::Factory* factory = handles.main_isolate()->factory(); |
| 1057 BytecodeArrayBuilder builder(handles.main_isolate(), |
| 1058 handles.main_zone()); |
| 1059 Register r0(0); |
| 1060 builder.set_locals_count(1); |
| 1061 builder.set_parameter_count(0); |
| 1062 builder.LoadLiteral(factory->NewHeapNumber(inputs[i])) |
| 1063 .StoreAccumulatorInRegister(r0) |
| 1064 .LoadLiteral(factory->NewHeapNumber(inputs[j])) |
| 1065 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
| 1066 .Return(); |
| 1067 |
| 1068 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 1069 InterpreterTester tester(handles.main_isolate(), bytecode_array); |
| 1070 auto callable = tester.GetCallable<>(); |
| 1071 Handle<Object> return_value = callable().ToHandleChecked(); |
| 1072 CHECK(return_value->IsBoolean()); |
| 1073 CHECK_EQ(return_value->BooleanValue(), |
| 1074 CompareC(comparison, inputs[i], inputs[j])); |
| 1075 } |
| 1076 } |
| 1077 } |
| 1078 } |
| 1079 |
| 1080 |
| 1081 TEST(InterpreterStringComparisons) { |
| 1082 std::string inputs[] = {"A", "abc", "z", "", "Foo!", "Foo"}; |
| 1083 |
| 1084 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { |
| 1085 Token::Value comparison = kComparisonTypes[c]; |
| 1086 for (size_t i = 0; i < arraysize(inputs); i++) { |
| 1087 for (size_t j = 0; j < arraysize(inputs); j++) { |
| 1088 const char* lhs = inputs[i].c_str(); |
| 1089 const char* rhs = inputs[j].c_str(); |
| 1090 HandleAndZoneScope handles; |
| 1091 i::Factory* factory = handles.main_isolate()->factory(); |
| 1092 BytecodeArrayBuilder builder(handles.main_isolate(), |
| 1093 handles.main_zone()); |
| 1094 Register r0(0); |
| 1095 builder.set_locals_count(1); |
| 1096 builder.set_parameter_count(0); |
| 1097 builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs)) |
| 1098 .StoreAccumulatorInRegister(r0) |
| 1099 .LoadLiteral(factory->NewStringFromAsciiChecked(rhs)) |
| 1100 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
| 1101 .Return(); |
| 1102 |
| 1103 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 1104 InterpreterTester tester(handles.main_isolate(), bytecode_array); |
| 1105 auto callable = tester.GetCallable<>(); |
| 1106 Handle<Object> return_value = callable().ToHandleChecked(); |
| 1107 CHECK(return_value->IsBoolean()); |
| 1108 CHECK_EQ(return_value->BooleanValue(), |
| 1109 CompareC(comparison, inputs[i], inputs[j])); |
| 1110 } |
| 1111 } |
| 1112 } |
| 1113 } |
| 1114 |
| 1115 |
| 1116 TEST(InterpreterMixedComparisons) { |
| 1117 // This test compares a HeapNumber with a String. The latter is |
| 1118 // convertible to a HeapNumber so comparison will be between numeric |
| 1119 // values except for the strict comparisons where no conversion is |
| 1120 // performed. |
| 1121 const char* inputs[] = {"-1.77", "-40.333", "0.01", "55.77e5", "2.01"}; |
| 1122 |
| 1123 i::UnicodeCache unicode_cache; |
| 1124 |
| 1125 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { |
| 1126 Token::Value comparison = kComparisonTypes[c]; |
| 1127 for (size_t i = 0; i < arraysize(inputs); i++) { |
| 1128 for (size_t j = 0; j < arraysize(inputs); j++) { |
| 1129 for (int pass = 0; pass < 2; pass++) { |
| 1130 const char* lhs_cstr = inputs[i]; |
| 1131 const char* rhs_cstr = inputs[j]; |
| 1132 double lhs = StringToDouble(&unicode_cache, lhs_cstr, |
| 1133 i::ConversionFlags::NO_FLAGS); |
| 1134 double rhs = StringToDouble(&unicode_cache, rhs_cstr, |
| 1135 i::ConversionFlags::NO_FLAGS); |
| 1136 HandleAndZoneScope handles; |
| 1137 i::Factory* factory = handles.main_isolate()->factory(); |
| 1138 BytecodeArrayBuilder builder(handles.main_isolate(), |
| 1139 handles.main_zone()); |
| 1140 Register r0(0); |
| 1141 builder.set_locals_count(1); |
| 1142 builder.set_parameter_count(0); |
| 1143 if (pass == 0) { |
| 1144 // Comparison with HeapNumber on the lhs and String on the rhs |
| 1145 builder.LoadLiteral(factory->NewNumber(lhs)) |
| 1146 .StoreAccumulatorInRegister(r0) |
| 1147 .LoadLiteral(factory->NewStringFromAsciiChecked(rhs_cstr)) |
| 1148 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
| 1149 .Return(); |
| 1150 } else { |
| 1151 // Comparison with HeapNumber on the rhs and String on the lhs |
| 1152 builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs_cstr)) |
| 1153 .StoreAccumulatorInRegister(r0) |
| 1154 .LoadLiteral(factory->NewNumber(rhs)) |
| 1155 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
| 1156 .Return(); |
| 1157 } |
| 1158 |
| 1159 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 1160 InterpreterTester tester(handles.main_isolate(), bytecode_array); |
| 1161 auto callable = tester.GetCallable<>(); |
| 1162 Handle<Object> return_value = callable().ToHandleChecked(); |
| 1163 CHECK(return_value->IsBoolean()); |
| 1164 CHECK_EQ(return_value->BooleanValue(), |
| 1165 CompareC(comparison, lhs, rhs, true)); |
| 1166 } |
| 1167 } |
| 1168 } |
| 1169 } |
| 1170 } |
| 1171 |
| 1172 |
| 1173 TEST(InterpreterInstanceOf) { |
| 1174 HandleAndZoneScope handles; |
| 1175 i::Factory* factory = handles.main_isolate()->factory(); |
| 1176 Handle<i::String> name = factory->NewStringFromAsciiChecked("cons"); |
| 1177 Handle<i::JSFunction> func = factory->NewFunction(name); |
| 1178 Handle<i::JSObject> instance = factory->NewJSObject(func); |
| 1179 Handle<i::Object> other = factory->NewNumber(3.3333); |
| 1180 Handle<i::Object> cases[] = { Handle<i::Object>::cast(instance), other }; |
| 1181 for (size_t i = 0; i < arraysize(cases); i++) { |
| 1182 bool expected_value = (i == 0); |
| 1183 BytecodeArrayBuilder builder(handles.main_isolate(), |
| 1184 handles.main_zone()); |
| 1185 Register r0(0); |
| 1186 builder.set_locals_count(1); |
| 1187 builder.set_parameter_count(0); |
| 1188 builder.LoadLiteral(cases[i]); |
| 1189 builder.StoreAccumulatorInRegister(r0) |
| 1190 .LoadLiteral(func) |
| 1191 .CompareOperation(Token::Value::INSTANCEOF, r0, LanguageMode::SLOPPY) |
| 1192 .Return(); |
| 1193 |
| 1194 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 1195 InterpreterTester tester(handles.main_isolate(), bytecode_array); |
| 1196 auto callable = tester.GetCallable<>(); |
| 1197 Handle<Object> return_value = callable().ToHandleChecked(); |
| 1198 CHECK(return_value->IsBoolean()); |
| 1199 CHECK_EQ(return_value->BooleanValue(), expected_value); |
| 1200 } |
| 1201 } |
| 1202 |
| 1203 |
| 1204 TEST(InterpreterTestIn) { |
| 1205 HandleAndZoneScope handles; |
| 1206 i::Factory* factory = handles.main_isolate()->factory(); |
| 1207 Handle<i::String> name = factory->InternalizeUtf8String("Array"); |
| 1208 Handle<i::Object> fun_obj = Object::GetProperty( |
| 1209 handles.main_isolate()->global_object(), name).ToHandleChecked(); |
| 1210 Handle<i::JSFunction> function = Handle<i::JSFunction>::cast(fun_obj); |
| 1211 |
| 1212 // Allocate an array |
| 1213 Handle<i::JSObject> object = factory->NewJSObject(function); |
| 1214 Handle<i::JSArray> array = Handle<i::JSArray>::cast(object); |
| 1215 i::JSArray::Initialize(array, 0); |
| 1216 i::JSArray::SetLength(array, 0); |
| 1217 |
| 1218 // Check for these properties on the array object |
| 1219 const char* properties[] = { "length", "fuzzle", "x", "0" }; |
| 1220 for (size_t i = 0; i < arraysize(properties); i++) { |
| 1221 bool expected_value = (i == 0); |
| 1222 BytecodeArrayBuilder builder(handles.main_isolate(), |
| 1223 handles.main_zone()); |
| 1224 Register r0(0); |
| 1225 builder.set_locals_count(1); |
| 1226 builder.set_parameter_count(0); |
| 1227 builder.LoadLiteral(factory->NewStringFromAsciiChecked(properties[i])) |
| 1228 .StoreAccumulatorInRegister(r0) |
| 1229 .LoadLiteral(Handle<Object>::cast(array)) |
| 1230 .CompareOperation(Token::Value::IN, r0, LanguageMode::SLOPPY) |
| 1231 .Return(); |
| 1232 |
| 1233 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
| 1234 InterpreterTester tester(handles.main_isolate(), bytecode_array); |
| 1235 auto callable = tester.GetCallable<>(); |
| 1236 Handle<Object> return_value = callable().ToHandleChecked(); |
| 1237 CHECK(return_value->IsBoolean()); |
| 1238 CHECK_EQ(return_value->BooleanValue(), expected_value); |
| 1239 } |
| 1240 } |
OLD | NEW |