[Interpreter] Adds logical and/or and comma operators to interpreter

Adds support for following operators
 -Logical and
 -Logical or
 -Comma

Adds the above bytecodes, support to BytecodeGenerator and BytecodeArrayBuilder
to enable it's use, it's implementation and tests.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31281}
This commit is contained in:
mythria 2015-10-15 02:11:40 -07:00 committed by Commit bot
parent c7c7b598ee
commit 5a09f1b9a7
11 changed files with 474 additions and 110 deletions

View File

@ -560,6 +560,30 @@ void BytecodeGraphBuilder::VisitJumpIfFalseConstant(
}
void BytecodeGraphBuilder::VisitJumpIfToBooleanTrue(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitJumpIfToBooleanTrueConstant(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitJumpIfToBooleanFalse(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitJumpIfToBooleanFalseConstant(
const interpreter::BytecodeArrayIterator& iterator) {
UNIMPLEMENTED();
}
void BytecodeGraphBuilder::VisitReturn(
const interpreter::BytecodeArrayIterator& iterator) {
Node* control =

View File

@ -458,6 +458,10 @@ Bytecode BytecodeArrayBuilder::GetJumpWithConstantOperand(
return Bytecode::kJumpIfTrueConstant;
case Bytecode::kJumpIfFalse:
return Bytecode::kJumpIfFalseConstant;
case Bytecode::kJumpIfToBooleanTrue:
return Bytecode::kJumpIfToBooleanTrueConstant;
case Bytecode::kJumpIfToBooleanFalse:
return Bytecode::kJumpIfToBooleanFalseConstant;
default:
UNREACHABLE();
return Bytecode::kJumpConstant;
@ -546,6 +550,18 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) {
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfToBooleanTrue(
BytecodeLabel* label) {
return OutputJump(Bytecode::kJumpIfToBooleanTrue, label);
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfToBooleanFalse(
BytecodeLabel* label) {
return OutputJump(Bytecode::kJumpIfToBooleanFalse, label);
}
BytecodeArrayBuilder& BytecodeArrayBuilder::Return() {
Output(Bytecode::kReturn);
return_seen_in_block_ = true;

View File

@ -129,6 +129,11 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& Jump(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
// TODO(mythria) The following two functions should be merged into
// JumpIfTrue/False. These bytecodes should be automatically chosen rather
// than explicitly using them.
BytecodeArrayBuilder& JumpIfToBooleanTrue(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfToBooleanFalse(BytecodeLabel* label);
BytecodeArrayBuilder& Return();
BytecodeArrayBuilder& EnterBlock();

View File

@ -1059,9 +1059,13 @@ void BytecodeGenerator::VisitCountOperation(CountOperation* expr) {
void BytecodeGenerator::VisitBinaryOperation(BinaryOperation* binop) {
switch (binop->op()) {
case Token::COMMA:
VisitCommaExpression(binop);
break;
case Token::OR:
VisitLogicalOrExpression(binop);
break;
case Token::AND:
UNIMPLEMENTED();
VisitLogicalAndExpression(binop);
break;
default:
VisitArithmeticExpression(binop);
@ -1194,6 +1198,53 @@ void BytecodeGenerator::VisitSetHomeObject(Register value, Register home_object,
}
void BytecodeGenerator::VisitCommaExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
Visit(left);
Visit(right);
}
void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
// Short-circuit evaluation- If it is known that left is always true,
// no need to visit right
if (left->ToBooleanIsTrue()) {
Visit(left);
} else {
BytecodeLabel end_label;
Visit(left);
builder()->JumpIfToBooleanTrue(&end_label);
Visit(right);
builder()->Bind(&end_label);
}
}
void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
Expression* left = binop->left();
Expression* right = binop->right();
// Short-circuit evaluation- If it is known that left is always false,
// no need to visit right
if (left->ToBooleanIsFalse()) {
Visit(left);
} else {
BytecodeLabel end_label;
Visit(left);
builder()->JumpIfToBooleanFalse(&end_label);
Visit(right);
builder()->Bind(&end_label);
}
}
LanguageMode BytecodeGenerator::language_mode() const {
return info()->language_mode();
}

View File

@ -37,6 +37,9 @@ class BytecodeGenerator : public AstVisitor {
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
void VisitArithmeticExpression(BinaryOperation* binop);
void VisitCommaExpression(BinaryOperation* binop);
void VisitLogicalOrExpression(BinaryOperation* binop);
void VisitLogicalAndExpression(BinaryOperation* binop);
void VisitPropertyLoad(Register obj, Property* expr);
void VisitVariableLoad(Variable* variable, FeedbackVectorSlot slot);
void VisitVariableAssignment(Variable* variable, FeedbackVectorSlot slot);

View File

@ -161,7 +161,9 @@ OperandSize Bytecodes::SizeOfOperand(OperandType operand_type) {
// static
bool Bytecodes::IsJump(Bytecode bytecode) {
return bytecode == Bytecode::kJump || bytecode == Bytecode::kJumpIfTrue ||
bytecode == Bytecode::kJumpIfFalse;
bytecode == Bytecode::kJumpIfFalse ||
bytecode == Bytecode::kJumpIfToBooleanTrue ||
bytecode == Bytecode::kJumpIfToBooleanFalse;
}
@ -169,7 +171,9 @@ bool Bytecodes::IsJump(Bytecode bytecode) {
bool Bytecodes::IsJumpConstant(Bytecode bytecode) {
return bytecode == Bytecode::kJumpConstant ||
bytecode == Bytecode::kJumpIfTrueConstant ||
bytecode == Bytecode::kJumpIfFalseConstant;
bytecode == Bytecode::kJumpIfFalseConstant ||
bytecode == Bytecode::kJumpIfToBooleanTrueConstant ||
bytecode == Bytecode::kJumpIfToBooleanFalseConstant;
}

View File

@ -124,6 +124,10 @@ namespace interpreter {
V(JumpIfTrueConstant, OperandType::kIdx8) \
V(JumpIfFalse, OperandType::kImm8) \
V(JumpIfFalseConstant, OperandType::kIdx8) \
V(JumpIfToBooleanTrue, OperandType::kImm8) \
V(JumpIfToBooleanTrueConstant, OperandType::kIdx8) \
V(JumpIfToBooleanFalse, OperandType::kImm8) \
V(JumpIfToBooleanFalseConstant, OperandType::kIdx8) \
V(Return, OperandType::kNone)

View File

@ -738,6 +738,72 @@ void Interpreter::DoCreateLiteral(Runtime::FunctionId function_id,
}
// JumpIfToBooleanTrue <imm8>
//
// Jump by number of bytes represented by an immediate operand if the object
// referenced by the accumulator is true when the object is cast to boolean.
void Interpreter::DoJumpIfToBooleanTrue(
compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* relative_jump = __ BytecodeOperandImm8(0);
Node* to_boolean_value =
__ CallRuntime(Runtime::kInterpreterToBoolean, accumulator);
Node* true_value = __ BooleanConstant(true);
__ JumpIfWordEqual(to_boolean_value, true_value, relative_jump);
}
// JumpIfToBooleanTrueConstant <idx>
//
// Jump by number of bytes in the Smi in the |idx| entry in the constant pool
// if the object referenced by the accumulator is true when the object is cast
// to boolean.
void Interpreter::DoJumpIfToBooleanTrueConstant(
compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* to_boolean_value =
__ CallRuntime(Runtime::kInterpreterToBoolean, accumulator);
Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant);
Node* true_value = __ BooleanConstant(true);
__ JumpIfWordEqual(to_boolean_value, true_value, relative_jump);
}
// JumpIfToBooleanFalse <imm8>
//
// Jump by number of bytes represented by an immediate operand if the object
// referenced by the accumulator is false when the object is cast to boolean.
void Interpreter::DoJumpIfToBooleanFalse(
compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* relative_jump = __ BytecodeOperandImm8(0);
Node* to_boolean_value =
__ CallRuntime(Runtime::kInterpreterToBoolean, accumulator);
Node* false_value = __ BooleanConstant(false);
__ JumpIfWordEqual(to_boolean_value, false_value, relative_jump);
}
// JumpIfToBooleanFalseConstant <idx>
//
// Jump by number of bytes in the Smi in the |idx| entry in the constant pool
// if the object referenced by the accumulator is false when the object is cast
// to boolean.
void Interpreter::DoJumpIfToBooleanFalseConstant(
compiler::InterpreterAssembler* assembler) {
Node* accumulator = __ GetAccumulator();
Node* to_boolean_value =
__ CallRuntime(Runtime::kInterpreterToBoolean, accumulator);
Node* index = __ BytecodeOperandIdx8(0);
Node* constant = __ LoadConstantPoolEntry(index);
Node* relative_jump = __ SmiUntag(constant);
Node* false_value = __ BooleanConstant(false);
__ JumpIfWordEqual(to_boolean_value, false_value, relative_jump);
}
// CreateArrayLiteral <idx> <flags>
//
// Creates an array literal for literal index <idx> with flags <flags> and

View File

@ -235,166 +235,263 @@ TEST(PrimitiveExpressions) {
kPointerSize,
1,
6,
{
B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Return) //
},
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), //
B(Return)},
0},
{"var x = 0; return x + 3;",
2 * kPointerSize,
1,
12,
{
B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Add), R(1), //
B(Return) //
},
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Add), R(1), //
B(Return)},
0},
{"var x = 0; return x - 3;",
2 * kPointerSize,
1,
12,
{
B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Sub), R(1), //
B(Return) //
},
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Sub), R(1), //
B(Return)},
0},
{"var x = 4; return x * 3;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(4), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Mul), R(1), //
B(Return) //
},
{B(LdaSmi8), U8(4), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Mul), R(1), //
B(Return)},
0},
{"var x = 4; return x / 3;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(4), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Div), R(1), //
B(Return) //
},
{B(LdaSmi8), U8(4), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Div), R(1), //
B(Return)},
0},
{"var x = 4; return x % 3;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(4), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Mod), R(1), //
B(Return) //
},
{B(LdaSmi8), U8(4), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(Mod), R(1), //
B(Return)},
0},
{"var x = 1; return x | 2;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(2), //
B(BitwiseOr), R(1), //
B(Return) //
},
{B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(2), //
B(BitwiseOr), R(1), //
B(Return)},
0},
{"var x = 1; return x ^ 2;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(2), //
B(BitwiseXor), R(1), //
B(Return) //
},
{B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(2), //
B(BitwiseXor), R(1), //
B(Return)},
0},
{"var x = 1; return x & 2;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(2), //
B(BitwiseAnd), R(1), //
B(Return) //
},
{B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(2), //
B(BitwiseAnd), R(1), //
B(Return)},
0},
{"var x = 10; return x << 3;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftLeft), R(1), //
B(Return) //
},
{B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftLeft), R(1), //
B(Return)},
0},
{"var x = 10; return x >> 3;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftRight), R(1), //
B(Return) //
},
{B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftRight), R(1), //
B(Return)},
0},
{"var x = 10; return x >>> 3;",
2 * kPointerSize,
1,
13,
{
B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftRightLogical), R(1), //
B(Return) //
},
{B(LdaSmi8), U8(10), //
B(Star), R(0), //
B(Ldar), R(0), // Easy to spot r1 not really needed here.
B(Star), R(1), // Dead store.
B(LdaSmi8), U8(3), //
B(ShiftRightLogical), R(1), //
B(Return)},
0},
{"var x = 0; return (x, 3);",
1 * kPointerSize,
1,
8,
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), //
B(LdaSmi8), U8(3), //
B(Return)},
0}};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
TEST(LogicalExpressions) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
ExpectedSnippet<int> snippets[] = {
{"var x = 0; return x || 3;",
1 * kPointerSize,
1,
10,
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), //
B(JumpIfToBooleanTrue), U8(4), //
B(LdaSmi8), U8(3), //
B(Return)},
0},
{"var x = 0; return x && 3;",
1 * kPointerSize,
1,
10,
{B(LdaZero), //
B(Star), R(0), //
B(Ldar), R(0), //
B(JumpIfToBooleanFalse), U8(4), //
B(LdaSmi8), U8(3), //
B(Return)},
0},
{"var x = 1; var a = 2, b = 3; return x || ("
#define X "a, b, 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 X X X X X X X X X
#undef X
"3);",
3 * kPointerSize,
1,
283,
{B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(LdaSmi8), U8(2), //
B(Star), R(1), //
B(LdaSmi8), U8(3), //
B(Star), R(2), //
B(Ldar), R(0), //
B(JumpIfToBooleanTrueConstant), U8(0), //
#define X B(Ldar), R(1), B(Ldar), R(2), B(Ldar), R(1), B(Ldar), R(2),
X X X X X X X X X 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
B(LdaSmi8), U8(3), //
B(Return)},
1,
{268, 0, 0, 0}},
{"var x = 0; var a = 2, b = 3; return x && ("
#define X "a, b, 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 X X X X X X X X X
#undef X
"3);",
3 * kPointerSize,
1,
282,
{B(LdaZero), //
B(Star), R(0), //
B(LdaSmi8), U8(2), //
B(Star), R(1), //
B(LdaSmi8), U8(3), //
B(Star), R(2), //
B(Ldar), R(0), //
B(JumpIfToBooleanFalseConstant), U8(0), //
#define X B(Ldar), R(1), B(Ldar), R(2), B(Ldar), R(1), B(Ldar), R(2),
X X X X X X X X X 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
B(LdaSmi8), U8(3), //
B(Return)},
1,
{268, 0, 0, 0}},
{"return 0 && 3;",
0 * kPointerSize,
1,
2,
{B(LdaZero), //
B(Return)},
0},
{"return 1 || 3;",
0 * kPointerSize,
1,
3,
{B(LdaSmi8), U8(1), //
B(Return)},
0},
{"var x = 1; return x && 3 || 0, 1;",
1 * kPointerSize,
1,
16,
{B(LdaSmi8), U8(1), //
B(Star), R(0), //
B(Ldar), R(0), //
B(JumpIfToBooleanFalse), U8(4), //
B(LdaSmi8), U8(3), //
B(JumpIfToBooleanTrue), U8(3), //
B(LdaZero), //
B(LdaSmi8), U8(1), //
B(Return)},
0}};
for (size_t i = 0; i < arraysize(snippets); i++) {

View File

@ -1725,3 +1725,89 @@ TEST(InterpreterObjectLiterals) {
CHECK(return_value->SameValue(*literals[i].second));
}
}
TEST(InterpreterComma) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
std::pair<const char*, Handle<Object>> literals[6] = {
std::make_pair("var a; return 0, a;\n", factory->undefined_value()),
std::make_pair("return 'a', 2.2, 3;\n",
Handle<Object>(Smi::FromInt(3), isolate)),
std::make_pair("return 'a', 'b', 'c';\n",
factory->NewStringFromStaticChars("c")),
std::make_pair("return 3.2, 2.3, 4.5;\n", factory->NewNumber(4.5)),
std::make_pair("var a = 10; return b = a, b = b+1;\n",
Handle<Object>(Smi::FromInt(11), isolate)),
std::make_pair("var a = 10; return b = a, b = b+1, b + 10;\n",
Handle<Object>(Smi::FromInt(21), isolate))};
for (size_t i = 0; i < arraysize(literals); i++) {
std::string source(InterpreterTester::SourceForBody(literals[i].first));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*literals[i].second));
}
}
TEST(InterpreterLogicalOr) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
std::pair<const char*, Handle<Object>> literals[5] = {
std::make_pair("var a, b; return a || b;\n", factory->undefined_value()),
std::make_pair("var a, b = 10; return a || b;\n",
Handle<Object>(Smi::FromInt(10), isolate)),
std::make_pair("var a = '0', b = 10; return a || b;\n",
factory->NewStringFromStaticChars("0")),
std::make_pair("return 0 || 3.2;\n", factory->NewNumber(3.2)),
std::make_pair("return 'a' || 0;\n",
factory->NewStringFromStaticChars("a"))};
for (size_t i = 0; i < arraysize(literals); i++) {
std::string source(InterpreterTester::SourceForBody(literals[i].first));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*literals[i].second));
}
}
TEST(InterpreterLogicalAnd) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
std::pair<const char*, Handle<Object>> literals[7] = {
std::make_pair("var a, b = 10; return a && b;\n",
factory->undefined_value()),
std::make_pair("var a = 0, b = 10; return a && b / a;\n",
Handle<Object>(Smi::FromInt(0), isolate)),
std::make_pair("var a = '0', b = 10; return a && b;\n",
Handle<Object>(Smi::FromInt(10), isolate)),
std::make_pair("return 0.0 && 3.2;\n",
Handle<Object>(Smi::FromInt(0), isolate)),
std::make_pair("return 'a' && 'b';\n",
factory->NewStringFromStaticChars("b")),
std::make_pair("return 'a' && 0 || 'b', 'c';\n",
factory->NewStringFromStaticChars("c")),
std::make_pair("var x = 1, y = 3; return x && 0 + 1 || y;\n",
Handle<Object>(Smi::FromInt(1), isolate))};
for (size_t i = 0; i < arraysize(literals); i++) {
std::string source(InterpreterTester::SourceForBody(literals[i].first));
InterpreterTester tester(handles.main_isolate(), source.c_str());
auto callable = tester.GetCallable<>();
Handle<i::Object> return_value = callable().ToHandleChecked();
CHECK(return_value->SameValue(*literals[i].second));
}
}

View File

@ -111,13 +111,21 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
BytecodeLabel start;
builder.Bind(&start);
// Short jumps with Imm8 operands
builder.Jump(&start).JumpIfTrue(&start).JumpIfFalse(&start);
builder.Jump(&start)
.JumpIfTrue(&start)
.JumpIfFalse(&start)
.JumpIfToBooleanTrue(&start)
.JumpIfToBooleanFalse(&start);
// Insert dummy ops to force longer jumps
for (int i = 0; i < 128; i++) {
builder.LoadTrue();
}
// Longer jumps requiring Constant operand
builder.Jump(&start).JumpIfTrue(&start).JumpIfFalse(&start);
builder.Jump(&start)
.JumpIfTrue(&start)
.JumpIfFalse(&start)
.JumpIfToBooleanTrue(&start)
.JumpIfToBooleanFalse(&start);
builder.Return();
// Generate BytecodeArray.