Commit 17363fa4 authored by oth's avatar oth Committed by Commit bot

[Interpreter] Add interpreter support for compare ops and ToBoolean.

The comparison operators and ToBoolean are implemented by calling into
the runtime. There are new runtime methods are prefixed with Interpreter
to make use case clear.

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1369123002

Cr-Commit-Position: refs/heads/master@{#30983}
parent 4d03c3aa
......@@ -1156,6 +1156,7 @@ source_set("v8_base") {
"src/runtime/runtime-generator.cc",
"src/runtime/runtime-i18n.cc",
"src/runtime/runtime-internal.cc",
"src/runtime/runtime-interpreter.cc",
"src/runtime/runtime-json.cc",
"src/runtime/runtime-literals.cc",
"src/runtime/runtime-liveedit.cc",
......
......@@ -368,13 +368,13 @@ void BytecodeGraphBuilder::VisitTestGreaterThan(
}
void BytecodeGraphBuilder::VisitTestLessThanEqual(
void BytecodeGraphBuilder::VisitTestLessThanOrEqual(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitTestGreaterThanEqual(
void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
......
......@@ -289,9 +289,9 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
case Bytecode::kTestEqualStrict:
case Bytecode::kTestNotEqualStrict:
case Bytecode::kTestLessThan:
case Bytecode::kTestLessThanEqual:
case Bytecode::kTestLessThanOrEqual:
case Bytecode::kTestGreaterThan:
case Bytecode::kTestGreaterThanEqual:
case Bytecode::kTestGreaterThanOrEqual:
case Bytecode::kTestInstanceOf:
case Bytecode::kTestIn:
break;
......@@ -560,9 +560,9 @@ Bytecode BytecodeArrayBuilder::BytecodeForCompareOperation(Token::Value op) {
case Token::Value::GT:
return Bytecode::kTestGreaterThan;
case Token::Value::LTE:
return Bytecode::kTestLessThanEqual;
return Bytecode::kTestLessThanOrEqual;
case Token::Value::GTE:
return Bytecode::kTestGreaterThanEqual;
return Bytecode::kTestGreaterThanOrEqual;
case Token::Value::INSTANCEOF:
return Bytecode::kTestInstanceOf;
case Token::Value::IN:
......
......@@ -68,8 +68,8 @@ namespace interpreter {
V(TestNotEqualStrict, OperandType::kReg) \
V(TestLessThan, OperandType::kReg) \
V(TestGreaterThan, OperandType::kReg) \
V(TestLessThanEqual, OperandType::kReg) \
V(TestGreaterThanEqual, OperandType::kReg) \
V(TestLessThanOrEqual, OperandType::kReg) \
V(TestGreaterThanOrEqual, OperandType::kReg) \
V(TestInstanceOf, OperandType::kReg) \
V(TestIn, OperandType::kReg) \
\
......
......@@ -294,15 +294,6 @@ void Interpreter::DoBinaryOp(Runtime::FunctionId function_id,
}
void Interpreter::DoCompareOp(Token::Value op,
compiler::InterpreterAssembler* assembler) {
// TODO(oth): placeholder until compare path fixed.
// The accumulator should be set to true on success (or false otherwise)
// by the comparisons so it can be used for conditional jumps.
DoLdaTrue(assembler);
}
// Add <src>
//
// Add register <src> to accumulator.
......@@ -363,7 +354,7 @@ void Interpreter::DoCall(compiler::InterpreterAssembler* assembler) {
//
// Test if the value in the <src> register equals the accumulator.
void Interpreter::DoTestEqual(compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::EQ, assembler);
DoBinaryOp(Runtime::kInterpreterEquals, assembler);
}
......@@ -371,7 +362,7 @@ void Interpreter::DoTestEqual(compiler::InterpreterAssembler* assembler) {
//
// Test if the value in the <src> register is not equal to the accumulator.
void Interpreter::DoTestNotEqual(compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::NE, assembler);
DoBinaryOp(Runtime::kInterpreterNotEquals, assembler);
}
......@@ -379,7 +370,7 @@ void Interpreter::DoTestNotEqual(compiler::InterpreterAssembler* assembler) {
//
// Test if the value in the <src> register is strictly equal to the accumulator.
void Interpreter::DoTestEqualStrict(compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::EQ_STRICT, assembler);
DoBinaryOp(Runtime::kInterpreterStrictEquals, assembler);
}
......@@ -389,7 +380,7 @@ void Interpreter::DoTestEqualStrict(compiler::InterpreterAssembler* assembler) {
// accumulator.
void Interpreter::DoTestNotEqualStrict(
compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::NE_STRICT, assembler);
DoBinaryOp(Runtime::kInterpreterStrictNotEquals, assembler);
}
......@@ -397,7 +388,7 @@ void Interpreter::DoTestNotEqualStrict(
//
// Test if the value in the <src> register is less than the accumulator.
void Interpreter::DoTestLessThan(compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::LT, assembler);
DoBinaryOp(Runtime::kInterpreterLessThan, assembler);
}
......@@ -405,36 +396,36 @@ void Interpreter::DoTestLessThan(compiler::InterpreterAssembler* assembler) {
//
// Test if the value in the <src> register is greater than the accumulator.
void Interpreter::DoTestGreaterThan(compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::GT, assembler);
DoBinaryOp(Runtime::kInterpreterGreaterThan, assembler);
}
// TestLessThanEqual <src>
// TestLessThanOrEqual <src>
//
// Test if the value in the <src> register is less than or equal to the
// accumulator.
void Interpreter::DoTestLessThanEqual(
void Interpreter::DoTestLessThanOrEqual(
compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::LTE, assembler);
DoBinaryOp(Runtime::kInterpreterLessThanOrEqual, assembler);
}
// TestGreaterThanEqual <src>
// TestGreaterThanOrEqual <src>
//
// Test if the value in the <src> register is greater than or equal to the
// accumulator.
void Interpreter::DoTestGreaterThanEqual(
void Interpreter::DoTestGreaterThanOrEqual(
compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::GTE, assembler);
DoBinaryOp(Runtime::kInterpreterGreaterThanOrEqual, assembler);
}
// TestIn <src>
//
// Test if the value in the <src> register is in the collection referenced
// by the accumulator.
// Test if the object referenced by the register operand is a property of the
// object referenced by the accumulator.
void Interpreter::DoTestIn(compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::IN, assembler);
DoBinaryOp(Runtime::kHasProperty, assembler);
}
......@@ -443,7 +434,7 @@ void Interpreter::DoTestIn(compiler::InterpreterAssembler* assembler) {
// Test if the object referenced by the <src> register is an an instance of type
// referenced by the accumulator.
void Interpreter::DoTestInstanceOf(compiler::InterpreterAssembler* assembler) {
DoCompareOp(Token::Value::INSTANCEOF, assembler);
DoBinaryOp(Runtime::kInstanceOf, assembler);
}
......
......@@ -815,7 +815,7 @@ enum CompareResult {
enum class ComparisonResult {
kLessThan, // x < y
kEqual, // x = y
kGreaterThan, // x > x
kGreaterThan, // x > y
kUndefined // at least one of x or y was undefined or NaN
};
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/runtime/runtime-utils.h"
#include "src/arguments.h"
#include "src/isolate-inl.h"
namespace v8 {
namespace internal {
RUNTIME_FUNCTION(Runtime_InterpreterEquals) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::Equals(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterNotEquals) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::Equals(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(!result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterLessThan) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::LessThan(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterGreaterThan) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::GreaterThan(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterLessThanOrEqual) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::LessThanOrEqual(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterGreaterThanOrEqual) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
Maybe<bool> result = Object::GreaterThanOrEqual(x, y);
if (result.IsJust()) {
return isolate->heap()->ToBoolean(result.FromJust());
} else {
return isolate->heap()->exception();
}
}
RUNTIME_FUNCTION(Runtime_InterpreterStrictEquals) {
SealHandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(Object, x, 0);
CONVERT_ARG_CHECKED(Object, y, 1);
return isolate->heap()->ToBoolean(x->StrictEquals(y));
}
RUNTIME_FUNCTION(Runtime_InterpreterStrictNotEquals) {
SealHandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(Object, x, 0);
CONVERT_ARG_CHECKED(Object, y, 1);
return isolate->heap()->ToBoolean(!x->StrictEquals(y));
}
RUNTIME_FUNCTION(Runtime_InterpreterToBoolean) {
SealHandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Object, x, 0);
return isolate->heap()->ToBoolean(x->BooleanValue());
}
} // namespace internal
} // namespace v8
......@@ -216,6 +216,18 @@ namespace internal {
F(ForInStep, 1, 1)
#define FOR_EACH_INTRINSIC_INTERPRETER(F) \
F(InterpreterEquals, 2, 1) \
F(InterpreterNotEquals, 2, 1) \
F(InterpreterStrictEquals, 2, 1) \
F(InterpreterStrictNotEquals, 2, 1) \
F(InterpreterLessThan, 2, 1) \
F(InterpreterGreaterThan, 2, 1) \
F(InterpreterLessThanOrEqual, 2, 1) \
F(InterpreterGreaterThanOrEqual, 2, 1) \
F(InterpreterToBoolean, 1, 1)
#define FOR_EACH_INTRINSIC_FUNCTION(F) \
F(FunctionGetName, 1, 1) \
F(FunctionSetName, 2, 1) \
......@@ -1058,6 +1070,7 @@ namespace internal {
FOR_EACH_INTRINSIC_DATE(F) \
FOR_EACH_INTRINSIC_DEBUG(F) \
FOR_EACH_INTRINSIC_FORIN(F) \
FOR_EACH_INTRINSIC_INTERPRETER(F) \
FOR_EACH_INTRINSIC_FUNCTION(F) \
FOR_EACH_INTRINSIC_FUTEX(F) \
FOR_EACH_INTRINSIC_GENERATOR(F) \
......
......@@ -18,7 +18,7 @@ class BytecodeGeneratorHelper {
public:
const char* kFunctionName = "f";
const int kLastParamIndex =
static const int kLastParamIndex =
-InterpreterFrameConstants::kLastParamFromRegisterPointer / kPointerSize;
BytecodeGeneratorHelper() {
......@@ -470,7 +470,7 @@ TEST(PropertyLoads) {
{"name"}}};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(snippets[i].code_snippet, "f");
helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
......@@ -573,7 +573,7 @@ TEST(PropertyStores) {
{"name"}}};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(snippets[i].code_snippet, "f");
helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
......@@ -651,7 +651,7 @@ TEST(PropertyCall) {
{"func"}}};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(snippets[i].code_snippet, "f");
helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
......@@ -681,7 +681,6 @@ TEST(LoadGlobal) {
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecode(snippets[i].code_snippet, "f");
bytecode_array->Print();
CheckBytecodeArrayEqual(snippets[i], bytecode_array, true);
}
}
......@@ -737,7 +736,7 @@ TEST(IfConditions) {
Handle<Object> unused = helper.factory()->undefined_value();
ExpectedSnippet<Handle<Object>> snippets[] = {
{"function f() { if (0) { return 1; } else { return -1; } }",
{"function f() { if (0) { return 1; } else { return -1; } } f()",
0,
1,
14,
......@@ -753,7 +752,7 @@ TEST(IfConditions) {
B(Return)}, //
0,
{unused, unused, unused, unused}},
{"function f() { if ('lucky') { return 1; } else { return -1; } }",
{"function f() { if ('lucky') { return 1; } else { return -1; } } f();",
0,
1,
15,
......@@ -768,9 +767,9 @@ TEST(IfConditions) {
B(LdaUndefined), //
B(Return)}, //
1,
{helper.factory()->NewStringFromStaticChars("lucky"), unused,
unused, unused}},
{"function f() { if (false) { return 1; } else { return -1; } }",
{helper.factory()->NewStringFromStaticChars("lucky"), unused, unused,
unused}},
{"function f() { if (false) { return 1; } else { return -1; } } f();",
0,
1,
13,
......@@ -785,26 +784,28 @@ TEST(IfConditions) {
B(Return)}, //
0,
{unused, unused, unused, unused}},
{"function f(a) { if (a <= 0) { return 200; } else { return -200; } }",
{"function f(a) { if (a <= 0) { return 200; } else { return -200; } }"
"f(99);",
kPointerSize,
2,
19,
{B(Ldar), R(-5), //
B(Star), R(0), //
B(LdaZero), //
B(TestLessThanEqual), R(0), //
B(JumpIfFalse), U8(7), //
B(LdaConstant), U8(0), //
B(Return), //
B(Jump), U8(5), // TODO(oth): Unreachable jump after return
B(LdaConstant), U8(1), //
B(Return), //
B(LdaUndefined), //
B(Return)}, //
{B(Ldar), R(-5), //
B(Star), R(0), //
B(LdaZero), //
B(TestLessThanOrEqual), R(0), //
B(JumpIfFalse), U8(7), //
B(LdaConstant), U8(0), //
B(Return), //
B(Jump), U8(5), // TODO(oth): Unreachable jump after return
B(LdaConstant), U8(1), //
B(Return), //
B(LdaUndefined), //
B(Return)}, //
2,
{helper.factory()->NewNumberFromInt(200),
helper.factory()->NewNumberFromInt(-200), unused, unused}},
{"function f(a, b) { if (a in b) { return 200; } }",
{"function f(a, b) { if (a in b) { return 200; } }"
"f('prop', { prop: 'yes'});",
kPointerSize,
3,
17,
......@@ -820,27 +821,11 @@ TEST(IfConditions) {
B(Return)}, //
1,
{helper.factory()->NewNumberFromInt(200), unused, unused, unused}},
{"function f(a, b) { if (a instanceof b) { return 200; } }",
kPointerSize,
3,
17,
{B(Ldar), R(-6), //
B(Star), R(0), //
B(Ldar), R(-5), //
B(TestInstanceOf), R(0), //
B(JumpIfFalse), U8(7), //
B(LdaConstant), U8(0), //
B(Return), //
B(Jump), U8(2), // TODO(oth): Unreachable jump after return
B(LdaUndefined), //
B(Return)}, //
1,
{helper.factory()->NewNumberFromInt(200), unused, unused, unused}},
{"function f(z) { var a = 0; var b = 0; if (a === 0.01) { "
#define X "b = a; a = b; "
X X X X X X X X X X X X X X X X X X X X X X X X
#undef X
" return 200; } else { return -200; } }",
" return 200; } else { return -200; } } f(0.001)",
3 * kPointerSize,
2,
218,
......@@ -868,11 +853,51 @@ TEST(IfConditions) {
{helper.factory()->NewHeapNumber(0.01),
helper.factory()->NewNumberFromInt(200),
helper.factory()->NewNumberFromInt(199),
helper.factory()->NewNumberFromInt(-200)}}};
helper.factory()->NewNumberFromInt(-200)}},
{"function f(a, b) {\n"
" if (a == b) { return 1; }\n"
" if (a === b) { return 1; }\n"
" if (a < b) { return 1; }\n"
" if (a > b) { return 1; }\n"
" if (a <= b) { return 1; }\n"
" if (a >= b) { return 1; }\n"
" if (a in b) { return 1; }\n"
" if (a instanceof b) { return 1; }\n"
" /* if (a != b) { return 1; } */" // TODO(oth) Ast visitor yields
" /* if (a !== b) { return 1; } */" // UNARY NOT, rather than !=/!==.
" return 0;\n"
"} f(1, 1);",
kPointerSize,
3,
122,
{
#define IF_CONDITION_RETURN(condition) \
B(Ldar), R(-6), \
B(Star), R(0), \
B(Ldar), R(-5), \
B(condition), R(0), \
B(JumpIfFalse), U8(7), \
B(LdaSmi8), U8(1), \
B(Return), \
B(Jump), U8(2),
IF_CONDITION_RETURN(TestEqual) //
IF_CONDITION_RETURN(TestEqualStrict) //
IF_CONDITION_RETURN(TestLessThan) //
IF_CONDITION_RETURN(TestGreaterThan) //
IF_CONDITION_RETURN(TestLessThanOrEqual) //
IF_CONDITION_RETURN(TestGreaterThanOrEqual) //
IF_CONDITION_RETURN(TestIn) //
IF_CONDITION_RETURN(TestInstanceOf) //
#undef IF_CONDITION_RETURN
B(LdaZero), //
B(Return)}, //
0,
{unused, unused, unused, unused}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecodeForFunction(snippets[i].code_snippet);
helper.MakeBytecode(snippets[i].code_snippet, helper.kFunctionName);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
......
This diff is collapsed.
// Copyright 2014 the V8 project authors. All rights reserved.
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/v8.h"
#include "src/factory.h"
#include "src/heap/heap.h"
#include "src/heap/heap-inl.h"
#include "src/runtime/runtime.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
namespace interpreter {
class RuntimeInterpreterTest : public TestWithIsolateAndZone {
public:
typedef Object* (*RuntimeMethod)(int, Object**, Isolate*);
RuntimeInterpreterTest() {}
~RuntimeInterpreterTest() override {}
bool TestOperatorWithObjects(RuntimeMethod method, Handle<Object> lhs,
Handle<Object> rhs, bool expected);
bool TestOperator(RuntimeMethod method, int32_t lhs, int32_t rhs,
bool expected);
bool TestOperator(RuntimeMethod method, double lhs, double rhs,
bool expected);
bool TestOperator(RuntimeMethod method, const char* lhs, const char* rhs,
bool expected);
};
bool RuntimeInterpreterTest::TestOperatorWithObjects(RuntimeMethod method,
Handle<Object> lhs,
Handle<Object> rhs,
bool expected) {
Object* args_object[] = {*rhs, *lhs};
Handle<Object> result =
handle(method(2, &args_object[1], isolate()), isolate());
CHECK(result->IsTrue() || result->IsFalse());
return result->IsTrue() == expected;
}
bool RuntimeInterpreterTest::TestOperator(RuntimeMethod method, int32_t lhs,
int32_t rhs, bool expected) {
Handle<Object> x = isolate()->factory()->NewNumberFromInt(lhs);
Handle<Object> y = isolate()->factory()->NewNumberFromInt(rhs);
return TestOperatorWithObjects(method, x, y, expected);
}
bool RuntimeInterpreterTest::TestOperator(RuntimeMethod method, double lhs,
double rhs, bool expected) {
Handle<Object> x = isolate()->factory()->NewNumber(lhs);
Handle<Object> y = isolate()->factory()->NewNumber(rhs);
CHECK_EQ(HeapNumber::cast(*x)->value(), lhs);
CHECK_EQ(HeapNumber::cast(*y)->value(), rhs);
return TestOperatorWithObjects(method, x, y, expected);
}
bool RuntimeInterpreterTest::TestOperator(RuntimeMethod method, const char* lhs,
const char* rhs, bool expected) {
Handle<Object> x = isolate()->factory()->NewStringFromAsciiChecked(lhs);
Handle<Object> y = isolate()->factory()->NewStringFromAsciiChecked(rhs);
return TestOperatorWithObjects(method, x, y, expected);
}
TEST_F(RuntimeInterpreterTest, TestOperatorsWithIntegers) {
int32_t inputs[] = {kMinInt, Smi::kMinValue, -17, -1, 0, 1,
991, Smi::kMaxValue, kMaxInt};
TRACED_FOREACH(int, lhs, inputs) {
TRACED_FOREACH(int, rhs, inputs) {
#define INTEGER_OPERATOR_CHECK(r, op, x, y) \
CHECK(TestOperator(Runtime_Interpreter##r, x, y, x op y))
INTEGER_OPERATOR_CHECK(Equals, ==, lhs, rhs);
INTEGER_OPERATOR_CHECK(NotEquals, !=, lhs, rhs);
INTEGER_OPERATOR_CHECK(StrictEquals, ==, lhs, rhs);
INTEGER_OPERATOR_CHECK(StrictNotEquals, !=, lhs, rhs);
INTEGER_OPERATOR_CHECK(LessThan, <, lhs, rhs);
INTEGER_OPERATOR_CHECK(GreaterThan, >, lhs, rhs);
INTEGER_OPERATOR_CHECK(LessThanOrEqual, <=, lhs, rhs);
INTEGER_OPERATOR_CHECK(GreaterThanOrEqual, >=, lhs, rhs);
#undef INTEGER_OPERATOR_CHECK
}
}
}
TEST_F(RuntimeInterpreterTest, TestOperatorsWithDoubles) {
double inputs[] = {std::numeric_limits<double>::min(),
std::numeric_limits<double>::max(),
-0.001,
0.01,
3.14,
-6.02214086e23};
TRACED_FOREACH(double, lhs, inputs) {
TRACED_FOREACH(double, rhs, inputs) {
#define DOUBLE_OPERATOR_CHECK(r, op, x, y) \
CHECK(TestOperator(Runtime_Interpreter##r, x, y, x op y))
DOUBLE_OPERATOR_CHECK(Equals, ==, lhs, rhs);
DOUBLE_OPERATOR_CHECK(NotEquals, !=, lhs, rhs);
DOUBLE_OPERATOR_CHECK(StrictEquals, ==, lhs, rhs);
DOUBLE_OPERATOR_CHECK(StrictNotEquals, !=, lhs, rhs);
DOUBLE_OPERATOR_CHECK(LessThan, <, lhs, rhs);
DOUBLE_OPERATOR_CHECK(GreaterThan, >, lhs, rhs);
DOUBLE_OPERATOR_CHECK(LessThanOrEqual, <=, lhs, rhs);
DOUBLE_OPERATOR_CHECK(GreaterThanOrEqual, >=, lhs, rhs);
#undef DOUBLE_OPERATOR_CHECK
}
}
}
TEST_F(RuntimeInterpreterTest, TestOperatorsWithString) {
const char* inputs[] = {"abc", "a", "def", "0"};
TRACED_FOREACH(const char*, lhs, inputs) {
TRACED_FOREACH(const char*, rhs, inputs) {
#define STRING_OPERATOR_CHECK(r, op, x, y) \
CHECK(TestOperator(Runtime_Interpreter##r, x, y, \
std::string(x) op std::string(y)))
STRING_OPERATOR_CHECK(Equals, ==, lhs, rhs);
STRING_OPERATOR_CHECK(NotEquals, !=, lhs, rhs);
STRING_OPERATOR_CHECK(StrictEquals, ==, lhs, rhs);
STRING_OPERATOR_CHECK(StrictNotEquals, !=, lhs, rhs);
STRING_OPERATOR_CHECK(LessThan, <, lhs, rhs);
STRING_OPERATOR_CHECK(GreaterThan, >, lhs, rhs);
STRING_OPERATOR_CHECK(LessThanOrEqual, <=, lhs, rhs);
STRING_OPERATOR_CHECK(GreaterThanOrEqual, >=, lhs, rhs);
#undef STRING_OPERATOR_CHECK
}
}
}
TEST_F(RuntimeInterpreterTest, ToBoolean) {
double quiet_nan = std::numeric_limits<double>::quiet_NaN();
std::pair<Handle<Object>, bool> cases[] = {
std::make_pair(isolate()->factory()->NewNumberFromInt(0), false),
std::make_pair(isolate()->factory()->NewNumberFromInt(1), true),
std::make_pair(isolate()->factory()->NewNumberFromInt(100), true),
std::make_pair(isolate()->factory()->NewNumberFromInt(-1), true),
std::make_pair(isolate()->factory()->NewNumber(7.7), true),
std::make_pair(isolate()->factory()->NewNumber(0.00001), true),
std::make_pair(isolate()->factory()->NewNumber(quiet_nan), false),
std::make_pair(isolate()->factory()->NewHeapNumber(0.0), false),
std::make_pair(isolate()->factory()->undefined_value(), false),
std::make_pair(isolate()->factory()->null_value(), false),
std::make_pair(isolate()->factory()->true_value(), true),
std::make_pair(isolate()->factory()->false_value(), false),
std::make_pair(isolate()->factory()->NewStringFromStaticChars(""), false),
std::make_pair(isolate()->factory()->NewStringFromStaticChars("_"), true),
};
for (size_t i = 0; i < arraysize(cases); i++) {
auto& value_expected_tuple = cases[i];
Object* args_object[] = {*value_expected_tuple.first};
Handle<Object> result = handle(
Runtime_InterpreterToBoolean(1, &args_object[0], isolate()), isolate());
CHECK(result->IsBoolean());
CHECK_EQ(result->IsTrue(), value_expected_tuple.second);
}
}
} // Namespace interpreter
} // namespace internal
} // namespace v8
......@@ -108,6 +108,7 @@
'heap/heap-unittest.cc',
'heap/scavenge-job-unittest.cc',
'run-all-unittests.cc',
'runtime/runtime-interpreter-unittest.cc',
'test-utils.h',
'test-utils.cc',
],
......
......@@ -922,6 +922,7 @@
'../../src/runtime/runtime-generator.cc',
'../../src/runtime/runtime-i18n.cc',
'../../src/runtime/runtime-internal.cc',
'../../src/runtime/runtime-interpreter.cc',
'../../src/runtime/runtime-json.cc',
'../../src/runtime/runtime-literals.cc',
'../../src/runtime/runtime-liveedit.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment