Chromium Code Reviews| 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, | |
| 1015 v8::internal::kMinInt / 4, | |
| 1016 -108733832, | |
| 1017 -999, | |
| 1018 -42, | |
| 1019 -2, | |
| 1020 -1, | |
| 1021 0, | |
| 1022 +1, | |
| 1023 +2, | |
| 1024 42, | |
| 1025 12345678, | |
| 1026 v8::internal::kMaxInt / 4, | |
| 1027 v8::internal::kMaxInt / 2}; | |
| 1028 | |
| 1029 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { | |
| 1030 Token::Value comparison = kComparisonTypes[c]; | |
| 1031 for (size_t i = 0; i < arraysize(inputs); i++) { | |
| 1032 for (size_t j = 0; j < arraysize(inputs); j++) { | |
| 1033 HandleAndZoneScope handles; | |
| 1034 BytecodeArrayBuilder builder(handles.main_isolate(), | |
| 1035 handles.main_zone()); | |
| 1036 Register r0(0); | |
| 1037 builder.set_locals_count(1); | |
| 1038 builder.set_parameter_count(0); | |
| 1039 builder.LoadLiteral(Smi::FromInt(inputs[i])) | |
| 1040 .StoreAccumulatorInRegister(r0) | |
| 1041 .LoadLiteral(Smi::FromInt(inputs[j])) | |
| 1042 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) | |
| 1043 .Return(); | |
| 1044 | |
| 1045 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | |
| 1046 InterpreterTester tester(handles.main_isolate(), bytecode_array); | |
| 1047 auto callable = tester.GetCallable<>(); | |
| 1048 Handle<Object> return_value = callable().ToHandleChecked(); | |
| 1049 CHECK(return_value->IsBoolean()); | |
| 1050 CHECK_EQ(return_value->BooleanValue(), | |
| 1051 CompareC(comparison, inputs[i], inputs[j])); | |
| 1052 } | |
| 1053 } | |
| 1054 } | |
| 1055 } | |
| 1056 | |
| 1057 | |
| 1058 TEST(InterpreterHeapNumberComparisons) { | |
| 1059 double inputs[] = {std::numeric_limits<double>::min(), | |
| 1060 std::numeric_limits<double>::max(), | |
| 1061 -0.001, | |
| 1062 0.01, | |
| 1063 0.1000001, | |
| 1064 1e99, | |
| 1065 -1e-99}; | |
| 1066 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { | |
| 1067 Token::Value comparison = kComparisonTypes[c]; | |
| 1068 for (size_t i = 0; i < arraysize(inputs); i++) { | |
| 1069 for (size_t j = 0; j < arraysize(inputs); j++) { | |
| 1070 HandleAndZoneScope handles; | |
| 1071 i::Factory* factory = handles.main_isolate()->factory(); | |
| 1072 BytecodeArrayBuilder builder(handles.main_isolate(), | |
| 1073 handles.main_zone()); | |
| 1074 Register r0(0); | |
| 1075 builder.set_locals_count(1); | |
| 1076 builder.set_parameter_count(0); | |
| 1077 builder.LoadLiteral(factory->NewHeapNumber(inputs[i])) | |
| 1078 .StoreAccumulatorInRegister(r0) | |
| 1079 .LoadLiteral(factory->NewHeapNumber(inputs[j])) | |
| 1080 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) | |
| 1081 .Return(); | |
| 1082 | |
| 1083 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | |
| 1084 InterpreterTester tester(handles.main_isolate(), bytecode_array); | |
| 1085 auto callable = tester.GetCallable<>(); | |
| 1086 Handle<Object> return_value = callable().ToHandleChecked(); | |
| 1087 CHECK(return_value->IsBoolean()); | |
| 1088 CHECK_EQ(return_value->BooleanValue(), | |
| 1089 CompareC(comparison, inputs[i], inputs[j])); | |
| 1090 } | |
| 1091 } | |
| 1092 } | |
| 1093 } | |
| 1094 | |
| 1095 | |
| 1096 TEST(InterpreterStringComparisons) { | |
| 1097 std::string inputs[] = {"A", "abc", "z", "", "Foo!", "Foo"}; | |
| 1098 | |
| 1099 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { | |
| 1100 Token::Value comparison = kComparisonTypes[c]; | |
| 1101 for (size_t i = 0; i < arraysize(inputs); i++) { | |
| 1102 for (size_t j = 0; j < arraysize(inputs); j++) { | |
| 1103 const char* lhs = inputs[i].c_str(); | |
| 1104 const char* rhs = inputs[j].c_str(); | |
| 1105 HandleAndZoneScope handles; | |
| 1106 i::Factory* factory = handles.main_isolate()->factory(); | |
| 1107 BytecodeArrayBuilder builder(handles.main_isolate(), | |
| 1108 handles.main_zone()); | |
| 1109 Register r0(0); | |
| 1110 builder.set_locals_count(1); | |
| 1111 builder.set_parameter_count(0); | |
| 1112 builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs)) | |
| 1113 .StoreAccumulatorInRegister(r0) | |
| 1114 .LoadLiteral(factory->NewStringFromAsciiChecked(rhs)) | |
| 1115 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) | |
| 1116 .Return(); | |
| 1117 | |
| 1118 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | |
| 1119 InterpreterTester tester(handles.main_isolate(), bytecode_array); | |
| 1120 auto callable = tester.GetCallable<>(); | |
| 1121 Handle<Object> return_value = callable().ToHandleChecked(); | |
| 1122 CHECK(return_value->IsBoolean()); | |
| 1123 CHECK_EQ(return_value->BooleanValue(), | |
| 1124 CompareC(comparison, inputs[i], inputs[j])); | |
| 1125 } | |
| 1126 } | |
| 1127 } | |
| 1128 } | |
| 1129 | |
| 1130 | |
| 1131 TEST(InterpreterMixedComparisons) { | |
| 1132 // This test compares a HeapNumber with a String. The latter is | |
| 1133 // convertible to a HeapNumber so comparison will be between numeric | |
| 1134 // values except for the strict comparisons where no conversion is | |
| 1135 // performed. | |
| 1136 const char* inputs[] = {"-1.77", "-40.333", "0.01", "55.77e5", "2.01"}; | |
| 1137 | |
| 1138 i::UnicodeCache unicode_cache; | |
| 1139 | |
| 1140 for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { | |
| 1141 Token::Value comparison = kComparisonTypes[c]; | |
| 1142 for (size_t i = 0; i < arraysize(inputs); i++) { | |
| 1143 for (size_t j = 0; j < arraysize(inputs); j++) { | |
| 1144 for (int pass = 0; pass < 2; pass++) { | |
| 1145 const char* lhs_cstr = inputs[i]; | |
| 1146 const char* rhs_cstr = inputs[j]; | |
| 1147 double lhs = StringToDouble(&unicode_cache, lhs_cstr, | |
| 1148 i::ConversionFlags::NO_FLAGS); | |
| 1149 double rhs = StringToDouble(&unicode_cache, rhs_cstr, | |
| 1150 i::ConversionFlags::NO_FLAGS); | |
| 1151 HandleAndZoneScope handles; | |
| 1152 i::Factory* factory = handles.main_isolate()->factory(); | |
| 1153 BytecodeArrayBuilder builder(handles.main_isolate(), | |
| 1154 handles.main_zone()); | |
| 1155 Register r0(0); | |
| 1156 builder.set_locals_count(1); | |
| 1157 builder.set_parameter_count(0); | |
| 1158 if (pass == 0) { | |
| 1159 // Comparison with HeapNumber on the lhs and String on the rhs | |
| 1160 builder.LoadLiteral(factory->NewNumber(lhs)) | |
| 1161 .StoreAccumulatorInRegister(r0) | |
| 1162 .LoadLiteral(factory->NewStringFromAsciiChecked(rhs_cstr)) | |
| 1163 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) | |
| 1164 .Return(); | |
| 1165 } else { | |
| 1166 // Comparison with HeapNumber on the rhs and String on the lhs | |
| 1167 builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs_cstr)) | |
| 1168 .StoreAccumulatorInRegister(r0) | |
| 1169 .LoadLiteral(factory->NewNumber(rhs)) | |
| 1170 .CompareOperation(comparison, r0, LanguageMode::SLOPPY) | |
| 1171 .Return(); | |
| 1172 } | |
| 1173 | |
| 1174 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | |
| 1175 InterpreterTester tester(handles.main_isolate(), bytecode_array); | |
| 1176 auto callable = tester.GetCallable<>(); | |
| 1177 Handle<Object> return_value = callable().ToHandleChecked(); | |
| 1178 CHECK(return_value->IsBoolean()); | |
| 1179 CHECK_EQ(return_value->BooleanValue(), | |
| 1180 CompareC(comparison, lhs, rhs, true)); | |
| 1181 } | |
| 1182 } | |
| 1183 } | |
| 1184 } | |
| 1185 } | |
| 1186 | |
| 1187 | |
| 1188 TEST(InterpreterInstanceOf) { | |
| 1189 HandleAndZoneScope handles; | |
| 1190 i::Factory* factory = handles.main_isolate()->factory(); | |
| 1191 Handle<i::String> name = factory->NewStringFromAsciiChecked("cons"); | |
| 1192 Handle<i::JSFunction> func = factory->NewFunction(name); | |
| 1193 Handle<i::JSObject> instance = factory->NewJSObject(func); | |
| 1194 Handle<i::Object> other = factory->NewNumber(3.3333); | |
| 1195 Handle<i::Object> cases[] = {Handle<i::Object>::cast(instance), other}; | |
| 1196 for (size_t i = 0; i < arraysize(cases); i++) { | |
| 1197 bool expected_value = (i == 0); | |
| 1198 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); | |
| 1199 Register r0(0); | |
| 1200 builder.set_locals_count(1); | |
| 1201 builder.set_parameter_count(0); | |
| 1202 builder.LoadLiteral(cases[i]); | |
| 1203 builder.StoreAccumulatorInRegister(r0) | |
| 1204 .LoadLiteral(func) | |
| 1205 .CompareOperation(Token::Value::INSTANCEOF, r0, LanguageMode::SLOPPY) | |
| 1206 .Return(); | |
| 1207 | |
| 1208 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | |
| 1209 InterpreterTester tester(handles.main_isolate(), bytecode_array); | |
| 1210 auto callable = tester.GetCallable<>(); | |
| 1211 Handle<Object> return_value = callable().ToHandleChecked(); | |
| 1212 CHECK(return_value->IsBoolean()); | |
| 1213 CHECK_EQ(return_value->BooleanValue(), expected_value); | |
| 1214 } | |
| 1215 } | |
| 1216 | |
| 1217 | |
| 1218 TEST(InterpreterTestIn) { | |
| 1219 HandleAndZoneScope handles; | |
| 1220 i::Factory* factory = handles.main_isolate()->factory(); | |
| 1221 Handle<i::String> name = factory->InternalizeUtf8String("Array"); | |
| 1222 Handle<i::Object> fun_obj = | |
| 1223 Object::GetProperty(handles.main_isolate()->global_object(), name) | |
| 1224 .ToHandleChecked(); | |
| 1225 Handle<i::JSFunction> function = Handle<i::JSFunction>::cast(fun_obj); | |
| 1226 | |
| 1227 // Allocate an array | |
| 1228 Handle<i::JSObject> object = factory->NewJSObject(function); | |
| 
 
rmcilroy
2015/09/28 14:30:39
nit - would factory->NewJSArray not do the job?
 
oth
2015/09/28 15:05:38
Done.
 
 | |
| 1229 Handle<i::JSArray> array = Handle<i::JSArray>::cast(object); | |
| 1230 i::JSArray::Initialize(array, 0); | |
| 1231 i::JSArray::SetLength(array, 0); | |
| 1232 | |
| 1233 // Check for these properties on the array object | |
| 1234 const char* properties[] = {"length", "fuzzle", "x", "0"}; | |
| 1235 for (size_t i = 0; i < arraysize(properties); i++) { | |
| 1236 bool expected_value = (i == 0); | |
| 1237 BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); | |
| 1238 Register r0(0); | |
| 1239 builder.set_locals_count(1); | |
| 1240 builder.set_parameter_count(0); | |
| 1241 builder.LoadLiteral(factory->NewStringFromAsciiChecked(properties[i])) | |
| 1242 .StoreAccumulatorInRegister(r0) | |
| 1243 .LoadLiteral(Handle<Object>::cast(array)) | |
| 1244 .CompareOperation(Token::Value::IN, r0, LanguageMode::SLOPPY) | |
| 1245 .Return(); | |
| 1246 | |
| 1247 Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); | |
| 1248 InterpreterTester tester(handles.main_isolate(), bytecode_array); | |
| 1249 auto callable = tester.GetCallable<>(); | |
| 1250 Handle<Object> return_value = callable().ToHandleChecked(); | |
| 1251 CHECK(return_value->IsBoolean()); | |
| 1252 CHECK_EQ(return_value->BooleanValue(), expected_value); | |
| 1253 } | |
| 1254 } | |
| OLD | NEW |