[Interpreter] Add conditional expressions.

Adds support and tests for conditional (ternary) expressions.

BUG=v8:4280
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#31575}
This commit is contained in:
rmcilroy 2015-10-26 08:31:05 -07:00 committed by Commit bot
parent cf050cc2d2
commit 2781ff6834
3 changed files with 100 additions and 1 deletions

View File

@ -656,7 +656,26 @@ void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
}
void BytecodeGenerator::VisitConditional(Conditional* expr) { UNIMPLEMENTED(); }
void BytecodeGenerator::VisitConditional(Conditional* expr) {
// TODO(rmcilroy): Spot easy cases where there code would not need to
// emit the then block or the else block, e.g. condition is
// obviously true/1/false/0.
BytecodeLabel else_label, end_label;
VisitForAccumulatorValue(expr->condition());
builder()->CastAccumulatorToBoolean();
builder()->JumpIfFalse(&else_label);
VisitForAccumulatorValue(expr->then_expression());
builder()->Jump(&end_label);
builder()->Bind(&else_label);
VisitForAccumulatorValue(expr->else_expression());
builder()->Bind(&end_label);
execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitLiteral(Literal* expr) {

View File

@ -3493,6 +3493,52 @@ TEST(IllegalRedeclaration) {
}
}
TEST(Conditional) {
InitializedHandleScope handle_scope;
BytecodeGeneratorHelper helper;
ExpectedSnippet<int> snippets[] = {
{"return 1 ? 2 : 3;",
0,
1,
12,
{
B(LdaSmi8), U8(1), //
B(ToBoolean), //
B(JumpIfFalse), U8(6), //
B(LdaSmi8), U8(2), //
B(Jump), U8(4), //
B(LdaSmi8), U8(3), //
B(Return), //
}},
{"return 1 ? 2 ? 3 : 4 : 5;",
0,
1,
21,
{
B(LdaSmi8), U8(1), //
B(ToBoolean), //
B(JumpIfFalse), U8(15), //
B(LdaSmi8), U8(2), //
B(ToBoolean), //
B(JumpIfFalse), U8(6), //
B(LdaSmi8), U8(3), //
B(Jump), U8(4), //
B(LdaSmi8), U8(4), //
B(Jump), U8(4), //
B(LdaSmi8), U8(5), //
B(Return), //
}},
};
for (size_t i = 0; i < arraysize(snippets); i++) {
Handle<BytecodeArray> bytecode_array =
helper.MakeBytecodeForFunctionBody(snippets[i].code_snippet);
CheckBytecodeArrayEqual(snippets[i], bytecode_array);
}
}
} // namespace interpreter
} // namespace internal
} // namespace v8

View File

@ -2264,3 +2264,37 @@ TEST(InterpreterCreateArguments) {
CHECK(return_val->SameValue(*args[create_args[i].second]));
}
}
TEST(InterpreterConditional) {
HandleAndZoneScope handles;
i::Isolate* isolate = handles.main_isolate();
std::pair<const char*, Handle<Object>> conditional[8] = {
std::make_pair("return true ? 2 : 3;",
handle(Smi::FromInt(2), isolate)),
std::make_pair("return false ? 2 : 3;",
handle(Smi::FromInt(3), isolate)),
std::make_pair("var a = 1; return a ? 20 : 30;",
handle(Smi::FromInt(20), isolate)),
std::make_pair("var a = 1; return a ? 20 : 30;",
handle(Smi::FromInt(20), isolate)),
std::make_pair("var a = 'string'; return a ? 20 : 30;",
handle(Smi::FromInt(20), isolate)),
std::make_pair("var a = undefined; return a ? 20 : 30;",
handle(Smi::FromInt(30), isolate)),
std::make_pair("return 1 ? 2 ? 3 : 4 : 5;",
handle(Smi::FromInt(3), isolate)),
std::make_pair("return 0 ? 2 ? 3 : 4 : 5;",
handle(Smi::FromInt(5), isolate)),
};
for (size_t i = 0; i < arraysize(conditional); i++) {
std::string source(InterpreterTester::SourceForBody(conditional[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(*conditional[i].second));
}
}