Index: test/cctest/interpreter/test-interpreter.cc |
diff --git a/test/cctest/interpreter/test-interpreter.cc b/test/cctest/interpreter/test-interpreter.cc |
index 7edf8d737e58d4838544924d55430440e3f9e7f1..bdd3573b79bb392148c7207e214cc28f0428979a 100644 |
--- a/test/cctest/interpreter/test-interpreter.cc |
+++ b/test/cctest/interpreter/test-interpreter.cc |
@@ -151,6 +151,7 @@ class InterpreterTester { |
using v8::internal::BytecodeArray; |
using v8::internal::Handle; |
+using v8::internal::LanguageMode; |
using v8::internal::Object; |
using v8::internal::Runtime; |
using v8::internal::Smi; |
@@ -976,3 +977,271 @@ TEST(InterpreterConditionalJumps) { |
Handle<Object> return_value = callable().ToHandleChecked(); |
CHECK_EQ(Smi::cast(*return_value)->value(), 7); |
} |
+ |
+ |
+static const Token::Value kComparisonTypes[] = { |
+ Token::Value::EQ, Token::Value::NE, Token::Value::EQ_STRICT, |
+ Token::Value::NE_STRICT, Token::Value::LTE, Token::Value::LTE, |
+ Token::Value::GT, Token::Value::GTE}; |
+ |
+ |
+template <typename T> |
+bool CompareC(Token::Value op, T lhs, T rhs, bool types_differed = false) { |
+ switch (op) { |
+ case Token::Value::EQ: |
+ return lhs == rhs; |
+ case Token::Value::NE: |
+ return lhs != rhs; |
+ case Token::Value::EQ_STRICT: |
+ return (lhs == rhs) && !types_differed; |
+ case Token::Value::NE_STRICT: |
+ return (lhs != rhs) || types_differed; |
+ case Token::Value::LT: |
+ return lhs < rhs; |
+ case Token::Value::LTE: |
+ return lhs <= rhs; |
+ case Token::Value::GT: |
+ return lhs > rhs; |
+ case Token::Value::GTE: |
+ return lhs >= rhs; |
+ default: |
+ UNREACHABLE(); |
+ return false; |
+ } |
+} |
+ |
+ |
+TEST(InterpreterSmiComparisons) { |
+ // NB Constants cover 31-bit space. |
+ int inputs[] = {v8::internal::kMinInt / 2, |
+ v8::internal::kMinInt / 4, |
+ -108733832, |
+ -999, |
+ -42, |
+ -2, |
+ -1, |
+ 0, |
+ +1, |
+ +2, |
+ 42, |
+ 12345678, |
+ v8::internal::kMaxInt / 4, |
+ v8::internal::kMaxInt / 2}; |
+ |
+ for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { |
+ Token::Value comparison = kComparisonTypes[c]; |
+ for (size_t i = 0; i < arraysize(inputs); i++) { |
+ for (size_t j = 0; j < arraysize(inputs); j++) { |
+ HandleAndZoneScope handles; |
+ BytecodeArrayBuilder builder(handles.main_isolate(), |
+ handles.main_zone()); |
+ Register r0(0); |
+ builder.set_locals_count(1); |
+ builder.set_parameter_count(0); |
+ builder.LoadLiteral(Smi::FromInt(inputs[i])) |
+ .StoreAccumulatorInRegister(r0) |
+ .LoadLiteral(Smi::FromInt(inputs[j])) |
+ .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
+ .Return(); |
+ |
+ Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
+ InterpreterTester tester(handles.main_isolate(), bytecode_array); |
+ auto callable = tester.GetCallable<>(); |
+ Handle<Object> return_value = callable().ToHandleChecked(); |
+ CHECK(return_value->IsBoolean()); |
+ CHECK_EQ(return_value->BooleanValue(), |
+ CompareC(comparison, inputs[i], inputs[j])); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+TEST(InterpreterHeapNumberComparisons) { |
+ double inputs[] = {std::numeric_limits<double>::min(), |
+ std::numeric_limits<double>::max(), |
+ -0.001, |
+ 0.01, |
+ 0.1000001, |
+ 1e99, |
+ -1e-99}; |
+ for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { |
+ Token::Value comparison = kComparisonTypes[c]; |
+ for (size_t i = 0; i < arraysize(inputs); i++) { |
+ for (size_t j = 0; j < arraysize(inputs); j++) { |
+ HandleAndZoneScope handles; |
+ i::Factory* factory = handles.main_isolate()->factory(); |
+ BytecodeArrayBuilder builder(handles.main_isolate(), |
+ handles.main_zone()); |
+ Register r0(0); |
+ builder.set_locals_count(1); |
+ builder.set_parameter_count(0); |
+ builder.LoadLiteral(factory->NewHeapNumber(inputs[i])) |
+ .StoreAccumulatorInRegister(r0) |
+ .LoadLiteral(factory->NewHeapNumber(inputs[j])) |
+ .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
+ .Return(); |
+ |
+ Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
+ InterpreterTester tester(handles.main_isolate(), bytecode_array); |
+ auto callable = tester.GetCallable<>(); |
+ Handle<Object> return_value = callable().ToHandleChecked(); |
+ CHECK(return_value->IsBoolean()); |
+ CHECK_EQ(return_value->BooleanValue(), |
+ CompareC(comparison, inputs[i], inputs[j])); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+TEST(InterpreterStringComparisons) { |
+ std::string inputs[] = {"A", "abc", "z", "", "Foo!", "Foo"}; |
+ |
+ for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { |
+ Token::Value comparison = kComparisonTypes[c]; |
+ for (size_t i = 0; i < arraysize(inputs); i++) { |
+ for (size_t j = 0; j < arraysize(inputs); j++) { |
+ const char* lhs = inputs[i].c_str(); |
+ const char* rhs = inputs[j].c_str(); |
+ HandleAndZoneScope handles; |
+ i::Factory* factory = handles.main_isolate()->factory(); |
+ BytecodeArrayBuilder builder(handles.main_isolate(), |
+ handles.main_zone()); |
+ Register r0(0); |
+ builder.set_locals_count(1); |
+ builder.set_parameter_count(0); |
+ builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs)) |
+ .StoreAccumulatorInRegister(r0) |
+ .LoadLiteral(factory->NewStringFromAsciiChecked(rhs)) |
+ .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
+ .Return(); |
+ |
+ Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
+ InterpreterTester tester(handles.main_isolate(), bytecode_array); |
+ auto callable = tester.GetCallable<>(); |
+ Handle<Object> return_value = callable().ToHandleChecked(); |
+ CHECK(return_value->IsBoolean()); |
+ CHECK_EQ(return_value->BooleanValue(), |
+ CompareC(comparison, inputs[i], inputs[j])); |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+TEST(InterpreterMixedComparisons) { |
+ // This test compares a HeapNumber with a String. The latter is |
+ // convertible to a HeapNumber so comparison will be between numeric |
+ // values except for the strict comparisons where no conversion is |
+ // performed. |
+ const char* inputs[] = {"-1.77", "-40.333", "0.01", "55.77e5", "2.01"}; |
+ |
+ i::UnicodeCache unicode_cache; |
+ |
+ for (size_t c = 0; c < arraysize(kComparisonTypes); c++) { |
+ Token::Value comparison = kComparisonTypes[c]; |
+ for (size_t i = 0; i < arraysize(inputs); i++) { |
+ for (size_t j = 0; j < arraysize(inputs); j++) { |
+ for (int pass = 0; pass < 2; pass++) { |
+ const char* lhs_cstr = inputs[i]; |
+ const char* rhs_cstr = inputs[j]; |
+ double lhs = StringToDouble(&unicode_cache, lhs_cstr, |
+ i::ConversionFlags::NO_FLAGS); |
+ double rhs = StringToDouble(&unicode_cache, rhs_cstr, |
+ i::ConversionFlags::NO_FLAGS); |
+ HandleAndZoneScope handles; |
+ i::Factory* factory = handles.main_isolate()->factory(); |
+ BytecodeArrayBuilder builder(handles.main_isolate(), |
+ handles.main_zone()); |
+ Register r0(0); |
+ builder.set_locals_count(1); |
+ builder.set_parameter_count(0); |
+ if (pass == 0) { |
+ // Comparison with HeapNumber on the lhs and String on the rhs |
+ builder.LoadLiteral(factory->NewNumber(lhs)) |
+ .StoreAccumulatorInRegister(r0) |
+ .LoadLiteral(factory->NewStringFromAsciiChecked(rhs_cstr)) |
+ .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
+ .Return(); |
+ } else { |
+ // Comparison with HeapNumber on the rhs and String on the lhs |
+ builder.LoadLiteral(factory->NewStringFromAsciiChecked(lhs_cstr)) |
+ .StoreAccumulatorInRegister(r0) |
+ .LoadLiteral(factory->NewNumber(rhs)) |
+ .CompareOperation(comparison, r0, LanguageMode::SLOPPY) |
+ .Return(); |
+ } |
+ |
+ Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
+ InterpreterTester tester(handles.main_isolate(), bytecode_array); |
+ auto callable = tester.GetCallable<>(); |
+ Handle<Object> return_value = callable().ToHandleChecked(); |
+ CHECK(return_value->IsBoolean()); |
+ CHECK_EQ(return_value->BooleanValue(), |
+ CompareC(comparison, lhs, rhs, true)); |
+ } |
+ } |
+ } |
+ } |
+} |
+ |
+ |
+TEST(InterpreterInstanceOf) { |
+ HandleAndZoneScope handles; |
+ i::Factory* factory = handles.main_isolate()->factory(); |
+ Handle<i::String> name = factory->NewStringFromAsciiChecked("cons"); |
+ Handle<i::JSFunction> func = factory->NewFunction(name); |
+ Handle<i::JSObject> instance = factory->NewJSObject(func); |
+ Handle<i::Object> other = factory->NewNumber(3.3333); |
+ Handle<i::Object> cases[] = {Handle<i::Object>::cast(instance), other}; |
+ for (size_t i = 0; i < arraysize(cases); i++) { |
+ bool expected_value = (i == 0); |
+ BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); |
+ Register r0(0); |
+ builder.set_locals_count(1); |
+ builder.set_parameter_count(0); |
+ builder.LoadLiteral(cases[i]); |
+ builder.StoreAccumulatorInRegister(r0) |
+ .LoadLiteral(func) |
+ .CompareOperation(Token::Value::INSTANCEOF, r0, LanguageMode::SLOPPY) |
+ .Return(); |
+ |
+ Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
+ InterpreterTester tester(handles.main_isolate(), bytecode_array); |
+ auto callable = tester.GetCallable<>(); |
+ Handle<Object> return_value = callable().ToHandleChecked(); |
+ CHECK(return_value->IsBoolean()); |
+ CHECK_EQ(return_value->BooleanValue(), expected_value); |
+ } |
+} |
+ |
+ |
+TEST(InterpreterTestIn) { |
+ HandleAndZoneScope handles; |
+ i::Factory* factory = handles.main_isolate()->factory(); |
+ // Allocate an array |
+ Handle<i::JSArray> array = |
+ factory->NewJSArray(i::ElementsKind::FAST_SMI_ELEMENTS); |
+ // Check for these properties on the array object |
+ const char* properties[] = {"length", "fuzzle", "x", "0"}; |
+ for (size_t i = 0; i < arraysize(properties); i++) { |
+ bool expected_value = (i == 0); |
+ BytecodeArrayBuilder builder(handles.main_isolate(), handles.main_zone()); |
+ Register r0(0); |
+ builder.set_locals_count(1); |
+ builder.set_parameter_count(0); |
+ builder.LoadLiteral(factory->NewStringFromAsciiChecked(properties[i])) |
+ .StoreAccumulatorInRegister(r0) |
+ .LoadLiteral(Handle<Object>::cast(array)) |
+ .CompareOperation(Token::Value::IN, r0, LanguageMode::SLOPPY) |
+ .Return(); |
+ |
+ Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(); |
+ InterpreterTester tester(handles.main_isolate(), bytecode_array); |
+ auto callable = tester.GetCallable<>(); |
+ Handle<Object> return_value = callable().ToHandleChecked(); |
+ CHECK(return_value->IsBoolean()); |
+ CHECK_EQ(return_value->BooleanValue(), expected_value); |
+ } |
+} |