Commit e66d4f87 authored by mythria's avatar mythria Committed by Commit bot

[Interpreter] Merges ToBoolean and JumpIfTrue/False bytecodes

Adds an optimization to emit JumpIfToBooleanTrue/False instead
of ToBoolean followed by JumpIfTrue/False if the value in the
accumulator is not boolean.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31697}
parent 7153c7f4
...@@ -480,10 +480,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) { ...@@ -480,10 +480,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::PopContext(Register context) {
} }
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { bool BytecodeArrayBuilder::NeedToBooleanCast() {
if (LastBytecodeInSameBlock()) { if (!LastBytecodeInSameBlock()) {
// If the previous bytecode puts a boolean in the accumulator // If the previous bytecode was from a different block return false.
// there is no need to emit an instruction. return true;
}
// If the previous bytecode puts a boolean in the accumulator return true.
switch (Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_))) { switch (Bytecodes::FromByte(bytecodes()->at(last_bytecode_start_))) {
case Bytecode::kToBoolean: case Bytecode::kToBoolean:
UNREACHABLE(); UNREACHABLE();
...@@ -500,13 +503,20 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() { ...@@ -500,13 +503,20 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
case Bytecode::kTestGreaterThanOrEqual: case Bytecode::kTestGreaterThanOrEqual:
case Bytecode::kTestInstanceOf: case Bytecode::kTestInstanceOf:
case Bytecode::kTestIn: case Bytecode::kTestIn:
return *this; case Bytecode::kForInDone:
return false;
default: default:
// Fall through to output kToBoolean. return true;
break;
}
} }
}
BytecodeArrayBuilder& BytecodeArrayBuilder::CastAccumulatorToBoolean() {
// If the previous bytecode puts a boolean in the accumulator
// there is no need to emit an instruction.
if (NeedToBooleanCast()) {
Output(Bytecode::kToBoolean); Output(Bytecode::kToBoolean);
}
return *this; return *this;
} }
...@@ -613,8 +623,32 @@ void BytecodeArrayBuilder::PatchJump( ...@@ -613,8 +623,32 @@ void BytecodeArrayBuilder::PatchJump(
} }
// static
Bytecode BytecodeArrayBuilder::GetJumpWithToBoolean(Bytecode jump_bytecode) {
switch (jump_bytecode) {
case Bytecode::kJump:
case Bytecode::kJumpIfNull:
case Bytecode::kJumpIfUndefined:
return jump_bytecode;
case Bytecode::kJumpIfTrue:
return Bytecode::kJumpIfToBooleanTrue;
case Bytecode::kJumpIfFalse:
return Bytecode::kJumpIfToBooleanFalse;
default:
UNREACHABLE();
}
return static_cast<Bytecode>(-1);
}
BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode, BytecodeArrayBuilder& BytecodeArrayBuilder::OutputJump(Bytecode jump_bytecode,
BytecodeLabel* label) { BytecodeLabel* label) {
// Check if the value in accumulator is boolean, if not choose an
// appropriate JumpIfToBoolean bytecode.
if (NeedToBooleanCast()) {
jump_bytecode = GetJumpWithToBoolean(jump_bytecode);
}
int delta; int delta;
if (label->is_bound()) { if (label->is_bound()) {
// Label has been bound already so this is a backwards jump. // Label has been bound already so this is a backwards jump.
...@@ -659,18 +693,6 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) { ...@@ -659,18 +693,6 @@ 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::JumpIfNull(BytecodeLabel* label) { BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNull(BytecodeLabel* label) {
return OutputJump(Bytecode::kJumpIfNull, label); return OutputJump(Bytecode::kJumpIfNull, label);
} }
......
...@@ -183,11 +183,6 @@ class BytecodeArrayBuilder { ...@@ -183,11 +183,6 @@ class BytecodeArrayBuilder {
BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label); BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label); BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label); BytecodeArrayBuilder& JumpIfUndefined(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& Throw(); BytecodeArrayBuilder& Throw();
BytecodeArrayBuilder& Return(); BytecodeArrayBuilder& Return();
...@@ -228,6 +223,7 @@ class BytecodeArrayBuilder { ...@@ -228,6 +223,7 @@ class BytecodeArrayBuilder {
static bool FitsInIdx16Operand(size_t value); static bool FitsInIdx16Operand(size_t value);
static Bytecode GetJumpWithConstantOperand(Bytecode jump_with_smi8_operand); static Bytecode GetJumpWithConstantOperand(Bytecode jump_with_smi8_operand);
static Bytecode GetJumpWithToBoolean(Bytecode jump);
template <size_t N> template <size_t N>
INLINE(void Output(Bytecode bytecode, uint32_t(&oprands)[N])); INLINE(void Output(Bytecode bytecode, uint32_t(&oprands)[N]));
...@@ -248,6 +244,8 @@ class BytecodeArrayBuilder { ...@@ -248,6 +244,8 @@ class BytecodeArrayBuilder {
uint32_t operand_value) const; uint32_t operand_value) const;
bool LastBytecodeInSameBlock() const; bool LastBytecodeInSameBlock() const;
bool NeedToBooleanCast();
int BorrowTemporaryRegister(); int BorrowTemporaryRegister();
void ReturnTemporaryRegister(int reg_index); void ReturnTemporaryRegister(int reg_index);
int PrepareForConsecutiveTemporaryRegisters(size_t count); int PrepareForConsecutiveTemporaryRegisters(size_t count);
......
...@@ -526,7 +526,6 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) { ...@@ -526,7 +526,6 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
BytecodeLabel else_label, end_label; BytecodeLabel else_label, end_label;
VisitForAccumulatorValue(stmt->condition()); VisitForAccumulatorValue(stmt->condition());
builder()->CastAccumulatorToBoolean();
builder()->JumpIfFalse(&else_label); builder()->JumpIfFalse(&else_label);
Visit(stmt->then_statement()); Visit(stmt->then_statement());
if (stmt->HasElseStatement()) { if (stmt->HasElseStatement()) {
...@@ -869,7 +868,6 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) { ...@@ -869,7 +868,6 @@ void BytecodeGenerator::VisitConditional(Conditional* expr) {
BytecodeLabel else_label, end_label; BytecodeLabel else_label, end_label;
VisitForAccumulatorValue(expr->condition()); VisitForAccumulatorValue(expr->condition());
builder()->CastAccumulatorToBoolean();
builder()->JumpIfFalse(&else_label); builder()->JumpIfFalse(&else_label);
VisitForAccumulatorValue(expr->then_expression()); VisitForAccumulatorValue(expr->then_expression());
...@@ -1869,7 +1867,7 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { ...@@ -1869,7 +1867,7 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) {
} else { } else {
BytecodeLabel end_label; BytecodeLabel end_label;
VisitForAccumulatorValue(left); VisitForAccumulatorValue(left);
builder()->JumpIfToBooleanTrue(&end_label); builder()->JumpIfTrue(&end_label);
VisitForAccumulatorValue(right); VisitForAccumulatorValue(right);
builder()->Bind(&end_label); builder()->Bind(&end_label);
} }
...@@ -1888,7 +1886,7 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { ...@@ -1888,7 +1886,7 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) {
} else { } else {
BytecodeLabel end_label; BytecodeLabel end_label;
VisitForAccumulatorValue(left); VisitForAccumulatorValue(left);
builder()->JumpIfToBooleanFalse(&end_label); builder()->JumpIfFalse(&end_label);
VisitForAccumulatorValue(right); VisitForAccumulatorValue(right);
builder()->Bind(&end_label); builder()->Bind(&end_label);
} }
......
...@@ -2027,7 +2027,9 @@ TEST(InterpreterLogicalOr) { ...@@ -2027,7 +2027,9 @@ TEST(InterpreterLogicalOr) {
factory->NewStringFromStaticChars("0")), factory->NewStringFromStaticChars("0")),
std::make_pair("return 0 || 3.2;\n", factory->NewNumber(3.2)), std::make_pair("return 0 || 3.2;\n", factory->NewNumber(3.2)),
std::make_pair("return 'a' || 0;\n", std::make_pair("return 'a' || 0;\n",
factory->NewStringFromStaticChars("a"))}; factory->NewStringFromStaticChars("a")),
std::make_pair("var a = '0', b = 10; return (a == 0) || b;\n",
factory->true_value())};
for (size_t i = 0; i < arraysize(literals); i++) { for (size_t i = 0; i < arraysize(literals); i++) {
std::string source(InterpreterTester::SourceForBody(literals[i].first)); std::string source(InterpreterTester::SourceForBody(literals[i].first));
...@@ -2052,14 +2054,15 @@ TEST(InterpreterLogicalAnd) { ...@@ -2052,14 +2054,15 @@ TEST(InterpreterLogicalAnd) {
handle(Smi::FromInt(0), isolate)), handle(Smi::FromInt(0), isolate)),
std::make_pair("var a = '0', b = 10; return a && b;\n", std::make_pair("var a = '0', b = 10; return a && b;\n",
handle(Smi::FromInt(10), isolate)), handle(Smi::FromInt(10), isolate)),
std::make_pair("return 0.0 && 3.2;\n", std::make_pair("return 0.0 && 3.2;\n", handle(Smi::FromInt(0), isolate)),
handle(Smi::FromInt(0), isolate)),
std::make_pair("return 'a' && 'b';\n", std::make_pair("return 'a' && 'b';\n",
factory->NewStringFromStaticChars("b")), factory->NewStringFromStaticChars("b")),
std::make_pair("return 'a' && 0 || 'b', 'c';\n", std::make_pair("return 'a' && 0 || 'b', 'c';\n",
factory->NewStringFromStaticChars("c")), factory->NewStringFromStaticChars("c")),
std::make_pair("var x = 1, y = 3; return x && 0 + 1 || y;\n", std::make_pair("var x = 1, y = 3; return x && 0 + 1 || y;\n",
handle(Smi::FromInt(1), isolate))}; handle(Smi::FromInt(1), isolate)),
std::make_pair("var x = 1, y = 3; return (x == 1) && (3 == 3) || y;\n",
factory->true_value())};
for (size_t i = 0; i < arraysize(literals); i++) { for (size_t i = 0; i < arraysize(literals); i++) {
std::string source(InterpreterTester::SourceForBody(literals[i].first)); std::string source(InterpreterTester::SourceForBody(literals[i].first));
...@@ -2529,6 +2532,64 @@ TEST(InterpreterGlobalDelete) { ...@@ -2529,6 +2532,64 @@ TEST(InterpreterGlobalDelete) {
} }
TEST(InterpreterBasicLoops) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
i::Factory* factory = isolate->factory();
std::pair<const char*, Handle<Object>> loops[] = {
std::make_pair("var a = 10; var b = 1;\n"
"while (a) {\n"
" b = b * 2;\n"
" a = a - 1;\n"
"};\n"
"return b;\n",
factory->NewHeapNumber(1024)),
std::make_pair("var a = 1; var b = 1;\n"
"do {\n"
" b = b * 2;\n"
" --a;\n"
"} while(a);\n"
"return b;\n",
handle(Smi::FromInt(2), isolate)),
std::make_pair("var b = 1;\n"
"for ( var a = 10; a; a--) {\n"
" b *= 2;\n"
"}\n"
"return b;",
factory->NewHeapNumber(1024)),
std::make_pair("var a = 10; var b = 1;\n"
"while (a > 0) {\n"
" b = b * 2;\n"
" a = a - 1;\n"
"};\n"
"return b;\n",
factory->NewHeapNumber(1024)),
std::make_pair("var a = 1; var b = 1;\n"
"do {\n"
" b = b * 2;\n"
" --a;\n"
"} while(a);\n"
"return b;\n",
handle(Smi::FromInt(2), isolate)),
std::make_pair("var b = 1;\n"
"for ( var a = 10; a > 0; a--) {\n"
" b *= 2;\n"
"}\n"
"return b;",
factory->NewHeapNumber(1024))};
for (size_t i = 0; i < arraysize(loops); i++) {
std::string source(InterpreterTester::SourceForBody(loops[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(*loops[i].second));
}
}
TEST(InterpreterForIn) { TEST(InterpreterForIn) {
HandleAndZoneScope handles; HandleAndZoneScope handles;
......
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