Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(480)

Unified Diff: src/interpreter/bytecode-generator.cc

Issue 2242463002: [interpreter] VisitForTest for bytecode generator (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: nit Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/bytecode-label.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/interpreter/bytecode-generator.cc
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc
index d5305fa84f9cfde746c437c3c0c86e96b7097163..d90603a25d81792c29df025efd45c4642b86b484 100644
--- a/src/interpreter/bytecode-generator.cc
+++ b/src/interpreter/bytecode-generator.cc
@@ -8,6 +8,7 @@
#include "src/code-stubs.h"
#include "src/compiler.h"
#include "src/interpreter/bytecode-flags.h"
+#include "src/interpreter/bytecode-label.h"
#include "src/interpreter/bytecode-register-allocator.h"
#include "src/interpreter/control-flow-builders.h"
#include "src/objects.h"
@@ -445,6 +446,12 @@ class BytecodeGenerator::ExpressionResultScope {
bool IsEffect() const { return kind_ == Expression::kEffect; }
bool IsValue() const { return kind_ == Expression::kValue; }
+ bool IsTest() const { return kind_ == Expression::kTest; }
+
+ TestResultScope* AsTest() {
+ DCHECK(IsTest());
+ return reinterpret_cast<TestResultScope*>(this);
+ }
virtual void SetResultInAccumulator() = 0;
virtual void SetResultInRegister(Register reg) = 0;
@@ -535,6 +542,61 @@ class BytecodeGenerator::RegisterResultScope final
Register result_register_;
};
+// Scoped class used when the result of the current expression to be
+// evaluated is only tested with jumps to two branches.
+class BytecodeGenerator::TestResultScope final : public ExpressionResultScope {
+ public:
+ TestResultScope(BytecodeGenerator* generator, BytecodeLabels* then_labels,
+ BytecodeLabels* else_labels, TestFallthrough fallthrough)
+ : ExpressionResultScope(generator, Expression::kTest),
+ then_labels_(then_labels),
+ else_labels_(else_labels),
+ fallthrough_(fallthrough),
+ result_consumed_by_test_(false) {}
+
+ virtual void SetResultInAccumulator() { set_result_identified(); }
+
+ virtual void SetResultInRegister(Register reg) {
+ builder()->LoadAccumulatorWithRegister(reg);
+ set_result_identified();
+ }
+
+ // Used when code special cases for TestResultScope and consumes any
+ // possible value by testing and jumping to a then/else label.
+ void SetResultConsumedByTest() {
+ result_consumed_by_test_ = true;
+ set_result_identified();
+ }
+
+ bool ResultConsumedByTest() { return result_consumed_by_test_; }
+
+ BytecodeLabel* NewThenLabel() { return then_labels_->New(); }
+ BytecodeLabel* NewElseLabel() { return else_labels_->New(); }
+
+ BytecodeLabels* then_labels() const { return then_labels_; }
+ BytecodeLabels* else_labels() const { return else_labels_; }
+
+ TestFallthrough fallthrough() const { return fallthrough_; }
+ TestFallthrough inverted_fallthrough() const {
+ switch (fallthrough_) {
+ case TestFallthrough::kThen:
+ return TestFallthrough::kElse;
+ case TestFallthrough::kElse:
+ return TestFallthrough::kThen;
+ default:
+ return TestFallthrough::kNone;
+ }
+ }
+
+ private:
+ BytecodeLabels* then_labels_;
+ BytecodeLabels* else_labels_;
+ TestFallthrough fallthrough_;
+ bool result_consumed_by_test_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestResultScope);
+};
+
// Used to build a list of global declaration initial value pairs.
class BytecodeGenerator::GlobalDeclarationsBuilder final : public ZoneObject {
public:
@@ -983,7 +1045,6 @@ void BytecodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
builder()->SetStatementPosition(stmt);
- BytecodeLabel else_label, end_label;
if (stmt->condition()->ToBooleanIsTrue()) {
// Generate then block unconditionally as always true.
Visit(stmt->then_statement());
@@ -996,15 +1057,20 @@ void BytecodeGenerator::VisitIfStatement(IfStatement* stmt) {
// TODO(oth): If then statement is BreakStatement or
// ContinueStatement we can reduce number of generated
// jump/jump_ifs here. See BasicLoops test.
- VisitForAccumulatorValue(stmt->condition());
- builder()->JumpIfFalse(&else_label);
+ BytecodeLabel end_label;
+ BytecodeLabels then_labels(zone()), else_labels(zone());
+ VisitForTest(stmt->condition(), &then_labels, &else_labels,
+ TestFallthrough::kThen);
+
+ then_labels.Bind(builder());
Visit(stmt->then_statement());
+
if (stmt->HasElseStatement()) {
builder()->Jump(&end_label);
- builder()->Bind(&else_label);
+ else_labels.Bind(builder());
Visit(stmt->else_statement());
} else {
- builder()->Bind(&else_label);
+ else_labels.Bind(builder());
}
builder()->Bind(&end_label);
}
@@ -1113,6 +1179,7 @@ void BytecodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
VisitIterationHeader(stmt, &loop_builder);
VisitIterationBody(stmt, &loop_builder);
builder()->SetExpressionAsStatementPosition(stmt->cond());
+ // TODO(klaasb) VisitForTest for loop conditions
VisitForAccumulatorValue(stmt->cond());
loop_builder.JumpToHeaderIfTrue();
}
@@ -1129,6 +1196,7 @@ void BytecodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
VisitIterationHeader(stmt, &loop_builder);
if (!stmt->cond()->ToBooleanIsTrue()) {
builder()->SetExpressionAsStatementPosition(stmt->cond());
+ // TODO(klaasb) VisitForTest for loop conditions
VisitForAccumulatorValue(stmt->cond());
loop_builder.BreakIfFalse();
}
@@ -1151,6 +1219,7 @@ void BytecodeGenerator::VisitForStatement(ForStatement* stmt) {
VisitIterationHeader(stmt, &loop_builder);
if (stmt->cond() && !stmt->cond()->ToBooleanIsTrue()) {
builder()->SetExpressionAsStatementPosition(stmt->cond());
+ // TODO(klaasb) VisitForTest for loop conditions
VisitForAccumulatorValue(stmt->cond());
loop_builder.BreakIfFalse();
}
@@ -1569,21 +1638,27 @@ void BytecodeGenerator::VisitDoExpression(DoExpression* expr) {
}
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;
+ if (expr->condition()->ToBooleanIsTrue()) {
+ // Generate then block unconditionally as always true.
+ VisitForAccumulatorValue(expr->then_expression());
+ } else if (expr->condition()->ToBooleanIsFalse()) {
+ // Generate else block unconditionally if it exists.
+ VisitForAccumulatorValue(expr->else_expression());
+ } else {
+ BytecodeLabel end_label;
+ BytecodeLabels then_labels(zone()), else_labels(zone());
- VisitForAccumulatorValue(expr->condition());
- builder()->JumpIfFalse(&else_label);
+ VisitForTest(expr->condition(), &then_labels, &else_labels,
+ TestFallthrough::kThen);
- VisitForAccumulatorValue(expr->then_expression());
- builder()->Jump(&end_label);
+ then_labels.Bind(builder());
+ VisitForAccumulatorValue(expr->then_expression());
+ builder()->Jump(&end_label);
- builder()->Bind(&else_label);
- VisitForAccumulatorValue(expr->else_expression());
- builder()->Bind(&end_label);
+ else_labels.Bind(builder());
+ VisitForAccumulatorValue(expr->else_expression());
+ builder()->Bind(&end_label);
+ }
execution_result()->SetResultInAccumulator();
}
@@ -1866,6 +1941,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
switch (variable->location()) {
case VariableLocation::LOCAL: {
Register source(Register(variable->index()));
+ // We need to load the variable into the accumulator, even when in a
+ // VisitForRegisterScope, in order to avoid register aliasing if
+ // subsequent expressions assign to the same variable.
builder()->LoadAccumulatorWithRegister(source);
BuildHoleCheckForVariableLoad(variable);
break;
@@ -1874,6 +1952,9 @@ void BytecodeGenerator::VisitVariableLoad(Variable* variable,
// The parameter indices are shifted by 1 (receiver is variable
// index -1 but is parameter index 0 in BytecodeArrayBuilder).
Register source = builder()->Parameter(variable->index() + 1);
+ // We need to load the variable into the accumulator, even when in a
+ // VisitForRegisterScope, in order to avoid register aliasing if
+ // subsequent expressions assign to the same variable.
builder()->LoadAccumulatorWithRegister(source);
BuildHoleCheckForVariableLoad(variable);
break;
@@ -2718,9 +2799,21 @@ void BytecodeGenerator::VisitTypeOf(UnaryOperation* expr) {
}
void BytecodeGenerator::VisitNot(UnaryOperation* expr) {
- VisitForAccumulatorValue(expr->expression());
- builder()->LogicalNot();
- execution_result()->SetResultInAccumulator();
+ if (execution_result()->IsEffect()) {
+ VisitForEffect(expr->expression());
+ } else if (execution_result()->IsTest()) {
+ TestResultScope* test_result = execution_result()->AsTest();
+ // No actual logical negation happening, we just swap the control flow by
+ // swapping the target labels and the fallthrough branch.
+ VisitForTest(expr->expression(), test_result->else_labels(),
+ test_result->then_labels(),
+ test_result->inverted_fallthrough());
+ test_result->SetResultConsumedByTest();
+ } else {
+ VisitForAccumulatorValue(expr->expression());
+ builder()->LogicalNot();
+ execution_result()->SetResultInAccumulator();
+ }
}
void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
@@ -2996,36 +3089,72 @@ 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()) {
- VisitForAccumulatorValue(left);
+ if (execution_result()->IsTest()) {
+ TestResultScope* test_result = execution_result()->AsTest();
+
+ if (left->ToBooleanIsTrue() || right->ToBooleanIsTrue()) {
+ builder()->Jump(test_result->NewThenLabel());
+ } else if (left->ToBooleanIsFalse() && right->ToBooleanIsFalse()) {
+ builder()->Jump(test_result->NewElseLabel());
+ } else {
+ BytecodeLabels test_right(zone());
+ VisitForTest(left, test_result->then_labels(), &test_right,
+ TestFallthrough::kElse);
+ test_right.Bind(builder());
+ VisitForTest(right, test_result->then_labels(),
+ test_result->else_labels(), test_result->fallthrough());
+ }
+ test_result->SetResultConsumedByTest();
} else {
- BytecodeLabel end_label;
- VisitForAccumulatorValue(left);
- builder()->JumpIfTrue(&end_label);
- VisitForAccumulatorValue(right);
- builder()->Bind(&end_label);
+ if (left->ToBooleanIsTrue()) {
+ VisitForAccumulatorValue(left);
+ } else if (left->ToBooleanIsFalse()) {
+ VisitForAccumulatorValue(right);
+ } else {
+ BytecodeLabel end_label;
+ VisitForAccumulatorValue(left);
+ builder()->JumpIfTrue(&end_label);
+ VisitForAccumulatorValue(right);
+ builder()->Bind(&end_label);
+ }
+ execution_result()->SetResultInAccumulator();
}
- execution_result()->SetResultInAccumulator();
}
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()) {
- VisitForAccumulatorValue(left);
+ if (execution_result()->IsTest()) {
+ TestResultScope* test_result = execution_result()->AsTest();
+
+ if (left->ToBooleanIsFalse() || right->ToBooleanIsFalse()) {
+ builder()->Jump(test_result->NewElseLabel());
+ } else if (left->ToBooleanIsTrue() && right->ToBooleanIsTrue()) {
+ builder()->Jump(test_result->NewThenLabel());
+ } else {
+ BytecodeLabels test_right(zone());
+ VisitForTest(left, &test_right, test_result->else_labels(),
+ TestFallthrough::kThen);
+ test_right.Bind(builder());
+ VisitForTest(right, test_result->then_labels(),
+ test_result->else_labels(), test_result->fallthrough());
+ }
+ test_result->SetResultConsumedByTest();
} else {
- BytecodeLabel end_label;
- VisitForAccumulatorValue(left);
- builder()->JumpIfFalse(&end_label);
- VisitForAccumulatorValue(right);
- builder()->Bind(&end_label);
+ if (left->ToBooleanIsFalse()) {
+ VisitForAccumulatorValue(left);
+ } else if (left->ToBooleanIsTrue()) {
+ VisitForAccumulatorValue(right);
+ } else {
+ BytecodeLabel end_label;
+ VisitForAccumulatorValue(left);
+ builder()->JumpIfFalse(&end_label);
+ VisitForAccumulatorValue(right);
+ builder()->Bind(&end_label);
+ }
+ execution_result()->SetResultInAccumulator();
}
- execution_result()->SetResultInAccumulator();
}
void BytecodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
@@ -3267,6 +3396,36 @@ void BytecodeGenerator::VisitForRegisterValue(Expression* expr,
builder()->StoreAccumulatorInRegister(destination);
}
+// Visits the expression |expr| for testing its boolean value and jumping to the
+// |then| or |other| label depending on value and short-circuit semantics
+void BytecodeGenerator::VisitForTest(Expression* expr,
+ BytecodeLabels* then_labels,
+ BytecodeLabels* else_labels,
+ TestFallthrough fallthrough) {
+ bool result_consumed;
+ {
+ // To make sure that all temporary registers are returned before generating
+ // jumps below, we ensure that the result scope is deleted before doing so.
+ // Dead registers might be materialized otherwise.
+ TestResultScope test_result(this, then_labels, else_labels, fallthrough);
+ Visit(expr);
+ result_consumed = test_result.ResultConsumedByTest();
+ }
+ if (!result_consumed) {
+ switch (fallthrough) {
+ case TestFallthrough::kThen:
+ builder()->JumpIfFalse(else_labels->New());
+ break;
+ case TestFallthrough::kElse:
+ builder()->JumpIfTrue(then_labels->New());
+ break;
+ case TestFallthrough::kNone:
+ builder()->JumpIfTrue(then_labels->New());
+ builder()->Jump(else_labels->New());
+ }
+ }
+}
+
void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) {
ContextScope context_scope(this, scope);
DCHECK(scope->declarations()->is_empty());
« no previous file with comments | « src/interpreter/bytecode-generator.h ('k') | src/interpreter/bytecode-label.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698