Index: src/interpreter/bytecode-generator.cc |
diff --git a/src/interpreter/bytecode-generator.cc b/src/interpreter/bytecode-generator.cc |
index 06f819e4a99c4cdf9580091c073d5a6bce6d074e..bfdc694892ad9e6599821effbffa603bd44a9f00 100644 |
--- a/src/interpreter/bytecode-generator.cc |
+++ b/src/interpreter/bytecode-generator.cc |
@@ -190,7 +190,7 @@ class BytecodeGenerator::ControlScope::DeferredCommands final { |
Entry& entry = deferred_[i]; |
builder()->LoadLiteral(Smi::FromInt(entry.token)); |
builder()->CompareOperation(Token::EQ_STRICT, token_register_); |
- dispatch.Case(static_cast<int>(i)); |
+ dispatch.Case(ToBooleanMode::kAlreadyBoolean, static_cast<int>(i)); |
} |
dispatch.DefaultAt(static_cast<int>(deferred_.size())); |
for (size_t i = 0; i < deferred_.size(); ++i) { |
@@ -411,9 +411,10 @@ class BytecodeGenerator::ExpressionResultScope { |
public: |
ExpressionResultScope(BytecodeGenerator* generator, Expression::Context kind) |
: generator_(generator), |
- kind_(kind), |
outer_(generator->execution_result()), |
- allocator_(generator) { |
+ allocator_(generator), |
+ kind_(kind), |
+ type_hint_(TypeHint::kAny) { |
generator_->set_execution_result(this); |
} |
@@ -430,11 +431,20 @@ class BytecodeGenerator::ExpressionResultScope { |
return reinterpret_cast<TestResultScope*>(this); |
} |
+ // Specify expression always returns a Boolean result value. |
+ void SetResultIsBoolean() { |
+ DCHECK(type_hint_ == TypeHint::kAny); |
+ type_hint_ = TypeHint::kBoolean; |
+ } |
+ |
+ TypeHint type_hint() const { return type_hint_; } |
+ |
private: |
BytecodeGenerator* generator_; |
- Expression::Context kind_; |
ExpressionResultScope* outer_; |
RegisterAllocationScope allocator_; |
+ Expression::Context kind_; |
+ TypeHint type_hint_; |
DISALLOW_COPY_AND_ASSIGN(ExpressionResultScope); |
}; |
@@ -473,8 +483,7 @@ class BytecodeGenerator::TestResultScope final : public ExpressionResultScope { |
void SetResultConsumedByTest() { |
result_consumed_by_test_ = true; |
} |
- |
- bool ResultConsumedByTest() { return result_consumed_by_test_; } |
+ bool result_consumed_by_test() { return result_consumed_by_test_; } |
BytecodeLabel* NewThenLabel() { return then_labels_->New(); } |
BytecodeLabel* NewElseLabel() { return else_labels_->New(); } |
@@ -794,7 +803,7 @@ void BytecodeGenerator::BuildIndexedJump(Register index, size_t start_index, |
builder() |
->LoadLiteral(Smi::FromInt(static_cast<int>(i))) |
.CompareOperation(Token::Value::EQ_STRICT, index) |
- .JumpIfTrue(&(targets[i])); |
+ .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &(targets[i])); |
} |
BuildAbort(BailoutReason::kInvalidJumpTableIndex); |
} |
@@ -828,7 +837,7 @@ void BytecodeGenerator::VisitIterationHeader(IterationStatement* stmt, |
builder() |
->LoadLiteral(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)) |
.CompareOperation(Token::Value::EQ_STRICT, generator_state_) |
- .JumpIfTrue(¬_resuming); |
+ .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, ¬_resuming); |
BuildIndexedJump(generator_state_, first_yield, stmt->suspend_count(), |
generator_resume_points_); |
builder()->Bind(¬_resuming); |
@@ -1142,7 +1151,7 @@ void BytecodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { |
builder()->CompareOperation( |
Token::Value::EQ_STRICT, tag, |
feedback_index(clause->CompareOperationFeedbackSlot())); |
- switch_builder.Case(i); |
+ switch_builder.Case(ToBooleanMode::kAlreadyBoolean, i); |
} |
if (default_index >= 0) { |
@@ -1344,7 +1353,7 @@ void BytecodeGenerator::VisitForInStatement(ForInStatement* stmt) { |
VisitIterationHeader(stmt, &loop_builder); |
builder()->SetExpressionAsStatementPosition(stmt->each()); |
builder()->ForInContinue(index, cache_length); |
- loop_builder.BreakIfFalse(); |
+ loop_builder.BreakIfFalse(ToBooleanMode::kAlreadyBoolean); |
FeedbackSlot slot = stmt->ForInFeedbackSlot(); |
builder()->ForInNext(receiver, index, triple.Truncate(2), |
feedback_index(slot)); |
@@ -1368,8 +1377,8 @@ void BytecodeGenerator::VisitForOfStatement(ForOfStatement* stmt) { |
VisitIterationHeader(stmt, &loop_builder); |
builder()->SetExpressionAsStatementPosition(stmt->next_result()); |
VisitForEffect(stmt->next_result()); |
- VisitForAccumulatorValue(stmt->result_done()); |
- loop_builder.BreakIfTrue(); |
+ TypeHint type_hint = VisitForAccumulatorValue(stmt->result_done()); |
+ loop_builder.BreakIfTrue(ToBooleanModeFromTypeHint(type_hint)); |
VisitForEffect(stmt->assign_each()); |
VisitIterationBody(stmt, &loop_builder); |
@@ -1562,7 +1571,7 @@ void BytecodeGenerator::VisitClassLiteralProperties(ClassLiteral* expr, |
builder() |
->LoadLiteral(ast_string_constants()->prototype_string()) |
.CompareOperation(Token::Value::EQ_STRICT, key) |
- .JumpIfFalse(&done) |
+ .JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done) |
.CallRuntime(Runtime::kThrowStaticPrototypeError) |
.Bind(&done); |
} |
@@ -1662,6 +1671,9 @@ void BytecodeGenerator::VisitLiteral(Literal* expr) { |
if (!execution_result()->IsEffect()) { |
const AstValue* raw_value = expr->raw_value(); |
builder()->LoadLiteral(raw_value); |
+ if (raw_value->IsTrue() || raw_value->IsFalse()) { |
+ execution_result()->SetResultIsBoolean(); |
+ } |
} |
} |
@@ -2450,10 +2462,10 @@ void BytecodeGenerator::VisitSuspend(Suspend* expr) { |
builder() |
->LoadLiteral(Smi::FromInt(JSGeneratorObject::kNext)) |
.CompareOperation(Token::EQ_STRICT, resume_mode) |
- .JumpIfTrue(&resume_with_next) |
+ .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_with_next) |
.LoadLiteral(Smi::FromInt(JSGeneratorObject::kThrow)) |
.CompareOperation(Token::EQ_STRICT, resume_mode) |
- .JumpIfTrue(&resume_with_throw) |
+ .JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &resume_with_throw) |
.Jump(&resume_with_return); |
builder()->Bind(&resume_with_return); |
@@ -2814,9 +2826,11 @@ void BytecodeGenerator::VisitNot(UnaryOperation* expr) { |
test_result->inverted_fallthrough()); |
test_result->SetResultConsumedByTest(); |
} else { |
- VisitForAccumulatorValue(expr->expression()); |
- builder()->LogicalNot(); |
+ TypeHint type_hint = VisitForAccumulatorValue(expr->expression()); |
+ builder()->LogicalNot(ToBooleanModeFromTypeHint(type_hint)); |
} |
+ // Always returns a boolean value. |
+ execution_result()->SetResultIsBoolean(); |
} |
void BytecodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { |
@@ -3095,6 +3109,8 @@ void BytecodeGenerator::VisitCompareOperation(CompareOperation* expr) { |
builder()->CompareOperation(expr->op(), lhs, feedback_index(slot)); |
} |
} |
+ // Always returns a boolean value. |
+ execution_result()->SetResultIsBoolean(); |
} |
void BytecodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) { |
@@ -3229,8 +3245,8 @@ void BytecodeGenerator::VisitLogicalOrExpression(BinaryOperation* binop) { |
VisitForAccumulatorValue(right); |
} else { |
BytecodeLabel end_label; |
- VisitForAccumulatorValue(left); |
- builder()->JumpIfTrue(&end_label); |
+ TypeHint type_hint = VisitForAccumulatorValue(left); |
+ builder()->JumpIfTrue(ToBooleanModeFromTypeHint(type_hint), &end_label); |
VisitForAccumulatorValue(right); |
builder()->Bind(&end_label); |
} |
@@ -3264,8 +3280,8 @@ void BytecodeGenerator::VisitLogicalAndExpression(BinaryOperation* binop) { |
VisitForAccumulatorValue(right); |
} else { |
BytecodeLabel end_label; |
- VisitForAccumulatorValue(left); |
- builder()->JumpIfFalse(&end_label); |
+ TypeHint type_hint = VisitForAccumulatorValue(left); |
+ builder()->JumpIfFalse(ToBooleanModeFromTypeHint(type_hint), &end_label); |
VisitForAccumulatorValue(right); |
builder()->Bind(&end_label); |
} |
@@ -3485,9 +3501,11 @@ void BytecodeGenerator::VisitFunctionClosureForContext() { |
} |
// Visits the expression |expr| and places the result in the accumulator. |
-void BytecodeGenerator::VisitForAccumulatorValue(Expression* expr) { |
+BytecodeGenerator::TypeHint BytecodeGenerator::VisitForAccumulatorValue( |
+ Expression* expr) { |
ValueResultScope accumulator_scope(this); |
Visit(expr); |
+ return accumulator_scope.type_hint(); |
} |
void BytecodeGenerator::VisitForAccumulatorValueOrTheHole(Expression* expr) { |
@@ -3551,24 +3569,27 @@ void BytecodeGenerator::VisitForTest(Expression* expr, |
BytecodeLabels* else_labels, |
TestFallthrough fallthrough) { |
bool result_consumed; |
+ TypeHint type_hint; |
{ |
// 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(); |
+ result_consumed = test_result.result_consumed_by_test(); |
+ type_hint = test_result.type_hint(); |
} |
if (!result_consumed) { |
+ ToBooleanMode mode(ToBooleanModeFromTypeHint(type_hint)); |
switch (fallthrough) { |
case TestFallthrough::kThen: |
- builder()->JumpIfFalse(else_labels->New()); |
+ builder()->JumpIfFalse(mode, else_labels->New()); |
break; |
case TestFallthrough::kElse: |
- builder()->JumpIfTrue(then_labels->New()); |
+ builder()->JumpIfTrue(mode, then_labels->New()); |
break; |
case TestFallthrough::kNone: |
- builder()->JumpIfTrue(then_labels->New()); |
+ builder()->JumpIfTrue(mode, then_labels->New()); |
builder()->Jump(else_labels->New()); |
} |
} |
@@ -3581,6 +3602,12 @@ void BytecodeGenerator::VisitInScope(Statement* stmt, Scope* scope) { |
Visit(stmt); |
} |
+BytecodeArrayBuilder::ToBooleanMode |
+BytecodeGenerator::ToBooleanModeFromTypeHint(TypeHint type_hint) { |
+ return type_hint == TypeHint::kBoolean ? ToBooleanMode::kAlreadyBoolean |
+ : ToBooleanMode::kConvertToBoolean; |
+} |
+ |
LanguageMode BytecodeGenerator::language_mode() const { |
return current_scope()->language_mode(); |
} |