Commit 7bedd111 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Interpreter] Move ToBoolean elision in BytecodeGenerator.

Move the ToBoolean elision in the BytecodeGenerator instead of the
peephole optimizer. Adds a TypeHint mechanism to the ExpressionResult
to enable passing of type hints through the ast visitor.

BUG=v8:6194

Change-Id: Ic55506ba11b213f7459250004d3f18cab04ee9b3
Reviewed-on: https://chromium-review.googlesource.com/467208
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarYang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44415}
parent 5e8eb624
......@@ -338,7 +338,6 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
typedef interpreter::Bytecodes Bytecodes;
if (Bytecodes::IsWithoutExternalSideEffects(bytecode)) return true;
if (Bytecodes::IsCallOrConstruct(bytecode)) return true;
if (Bytecodes::WritesBooleanToAccumulator(bytecode)) return true;
if (Bytecodes::IsJumpIfToBoolean(bytecode)) return true;
if (Bytecodes::IsPrefixScalingBytecode(bytecode)) return true;
switch (bytecode) {
......@@ -385,6 +384,20 @@ bool BytecodeHasNoSideEffect(interpreter::Bytecode bytecode) {
case Bytecode::kCreateClosure:
case Bytecode::kCreateUnmappedArguments:
case Bytecode::kCreateRestParameter:
// Comparisons.
case Bytecode::kTestEqual:
case Bytecode::kTestEqualStrict:
case Bytecode::kTestLessThan:
case Bytecode::kTestLessThanOrEqual:
case Bytecode::kTestGreaterThan:
case Bytecode::kTestGreaterThanOrEqual:
case Bytecode::kTestInstanceOf:
case Bytecode::kTestIn:
case Bytecode::kTestEqualStrictNoFeedback:
case Bytecode::kTestUndetectable:
case Bytecode::kTestTypeOf:
case Bytecode::kTestUndefined:
case Bytecode::kTestNull:
// Conversions.
case Bytecode::kToObject:
case Bytecode::kToNumber:
......
......@@ -328,8 +328,13 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::CountOperation(Token::Value op,
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot() {
OutputToBooleanLogicalNot();
BytecodeArrayBuilder& BytecodeArrayBuilder::LogicalNot(ToBooleanMode mode) {
if (mode == ToBooleanMode::kAlreadyBoolean) {
OutputLogicalNot();
} else {
DCHECK_EQ(mode, ToBooleanMode::kConvertToBoolean);
OutputToBooleanLogicalNot();
}
return *this;
}
......@@ -895,17 +900,27 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::Jump(BytecodeLabel* label) {
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(BytecodeLabel* label) {
// The peephole optimizer attempts to simplify JumpIfToBooleanTrue
// to JumpIfTrue.
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfTrue(ToBooleanMode mode,
BytecodeLabel* label) {
DCHECK(!label->is_bound());
OutputJumpIfToBooleanTrue(label, 0);
if (mode == ToBooleanMode::kAlreadyBoolean) {
OutputJumpIfTrue(label, 0);
} else {
DCHECK_EQ(mode, ToBooleanMode::kConvertToBoolean);
OutputJumpIfToBooleanTrue(label, 0);
}
return *this;
}
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(BytecodeLabel* label) {
BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfFalse(ToBooleanMode mode,
BytecodeLabel* label) {
DCHECK(!label->is_bound());
OutputJumpIfToBooleanFalse(label, 0);
if (mode == ToBooleanMode::kAlreadyBoolean) {
OutputJumpIfFalse(label, 0);
} else {
DCHECK_EQ(mode, ToBooleanMode::kConvertToBoolean);
OutputJumpIfToBooleanFalse(label, 0);
}
return *this;
}
......@@ -941,7 +956,8 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNil(BytecodeLabel* label,
NilValue nil) {
if (op == Token::EQ) {
// TODO(rmcilroy): Implement JumpIfUndetectable.
return CompareUndetectable().JumpIfTrue(label);
return CompareUndetectable().JumpIfTrue(ToBooleanMode::kAlreadyBoolean,
label);
} else {
DCHECK_EQ(Token::EQ_STRICT, op);
if (nil == kUndefinedValue) {
......@@ -958,7 +974,8 @@ BytecodeArrayBuilder& BytecodeArrayBuilder::JumpIfNotNil(BytecodeLabel* label,
NilValue nil) {
if (op == Token::EQ) {
// TODO(rmcilroy): Implement JumpIfUndetectable.
return CompareUndetectable().JumpIfFalse(label);
return CompareUndetectable().JumpIfFalse(ToBooleanMode::kAlreadyBoolean,
label);
} else {
DCHECK_EQ(Token::EQ_STRICT, op);
if (nil == kUndefinedValue) {
......@@ -1328,6 +1345,18 @@ uint32_t BytecodeArrayBuilder::GetOutputRegisterListOperand(
return static_cast<uint32_t>(reg_list.first_register().ToOperand());
}
std::ostream& operator<<(std::ostream& os,
const BytecodeArrayBuilder::ToBooleanMode& mode) {
switch (mode) {
case BytecodeArrayBuilder::ToBooleanMode::kAlreadyBoolean:
return os << "AlreadyBoolean";
case BytecodeArrayBuilder::ToBooleanMode::kConvertToBoolean:
return os << "ConvertToBoolean";
}
UNREACHABLE();
return os;
}
} // namespace interpreter
} // namespace internal
} // namespace v8
......@@ -297,8 +297,13 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
// Type feedback will be recorded in the |feedback_slot|
BytecodeArrayBuilder& CountOperation(Token::Value op, int feedback_slot);
enum class ToBooleanMode {
kConvertToBoolean, // Perform ToBoolean conversion on accumulator.
kAlreadyBoolean, // Accumulator is already a Boolean.
};
// Unary Operators.
BytecodeArrayBuilder& LogicalNot();
BytecodeArrayBuilder& LogicalNot(ToBooleanMode mode);
BytecodeArrayBuilder& TypeOf();
// Expects a heap object in the accumulator. Returns its super constructor in
......@@ -331,8 +336,10 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label);
BytecodeArrayBuilder& Jump(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth);
BytecodeArrayBuilder& JumpIfTrue(ToBooleanMode mode, BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfFalse(ToBooleanMode mode, BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfJSReceiver(BytecodeLabel* label);
BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
......@@ -343,7 +350,6 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
NilValue nil);
BytecodeArrayBuilder& JumpIfNotNil(BytecodeLabel* label, Token::Value op,
NilValue nil);
BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth);
BytecodeArrayBuilder& StackCheck(int position);
......@@ -505,6 +511,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
};
V8_EXPORT_PRIVATE std::ostream& operator<<(
std::ostream& os, const BytecodeArrayBuilder::ToBooleanMode& mode);
} // namespace interpreter
} // namespace internal
} // namespace v8
......
......@@ -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(&not_resuming);
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &not_resuming);
BuildIndexedJump(generator_state_, first_yield, stmt->suspend_count(),
generator_resume_points_);
builder()->Bind(&not_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();
}
......
......@@ -53,7 +53,10 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
class TestResultScope;
class ValueResultScope;
using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
enum class TestFallthrough { kThen, kElse, kNone };
enum class TypeHint { kAny, kBoolean };
void GenerateBytecodeBody();
void AllocateDeferredConstants(Isolate* isolate);
......@@ -161,8 +164,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildPushUndefinedIntoRegisterList(RegisterList* reg_list);
// Visitors for obtaining expression result in the accumulator, in a
// register, or just getting the effect.
void VisitForAccumulatorValue(Expression* expr);
// register, or just getting the effect. Some visitors return a TypeHint which
// specifies the type of the result of the visited expression.
TypeHint VisitForAccumulatorValue(Expression* expr);
void VisitForAccumulatorValueOrTheHole(Expression* expr);
MUST_USE_RESULT Register VisitForRegisterValue(Expression* expr);
void VisitForRegisterValue(Expression* expr, Register destination);
......@@ -176,6 +180,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
inline Runtime::FunctionId StoreToSuperRuntimeId();
inline Runtime::FunctionId StoreKeyedToSuperRuntimeId();
ToBooleanMode ToBooleanModeFromTypeHint(TypeHint type_hint);
inline BytecodeArrayBuilder* builder() const { return builder_; }
inline Zone* zone() const { return zone_; }
inline DeclarationScope* closure_scope() const { return closure_scope_; }
......
......@@ -269,16 +269,6 @@ void BytecodePeepholeOptimizer::UpdateLastJumpAction(
DCHECK(Bytecodes::IsJump(node->bytecode()));
}
void BytecodePeepholeOptimizer::ChangeJumpBytecodeAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
DCHECK(Bytecodes::IsJump(node->bytecode()));
next_stage()->Write(last());
InvalidateLast();
node->replace_bytecode(action_data->bytecode);
}
void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction(
BytecodeNode* const node, const PeepholeActionAndData* action_data) {
DCHECK(LastIsValid());
......
......@@ -25,7 +25,6 @@ namespace interpreter {
#define PEEPHOLE_JUMP_ACTION_LIST(V) \
V(DefaultJumpAction) \
V(UpdateLastJumpAction) \
V(ChangeJumpBytecodeAction) \
V(ElideLastBeforeJumpAction)
#define PEEPHOLE_ACTION_LIST(V) \
......
......@@ -500,33 +500,6 @@ class V8_EXPORT_PRIVATE Bytecodes final {
return BytecodeOperands::WritesAccumulator(GetAccumulatorUse(bytecode));
}
// Return true if |bytecode| writes the accumulator with a boolean value.
static bool WritesBooleanToAccumulator(Bytecode bytecode) {
switch (bytecode) {
case Bytecode::kLdaTrue:
case Bytecode::kLdaFalse:
case Bytecode::kToBooleanLogicalNot:
case Bytecode::kLogicalNot:
case Bytecode::kTestEqual:
case Bytecode::kTestEqualStrict:
case Bytecode::kTestLessThan:
case Bytecode::kTestLessThanOrEqual:
case Bytecode::kTestGreaterThan:
case Bytecode::kTestGreaterThanOrEqual:
case Bytecode::kTestInstanceOf:
case Bytecode::kTestIn:
case Bytecode::kTestEqualStrictNoFeedback:
case Bytecode::kTestUndetectable:
case Bytecode::kTestTypeOf:
case Bytecode::kForInContinue:
case Bytecode::kTestUndefined:
case Bytecode::kTestNull:
return true;
default:
return false;
}
}
// Return true if |bytecode| is an accumulator load without effects,
// e.g. LdaConstant, LdaTrue, Ldar.
static constexpr bool IsAccumulatorLoadWithoutEffects(Bytecode bytecode) {
......
......@@ -22,12 +22,14 @@ void BreakableControlFlowBuilder::EmitJump(BytecodeLabels* sites) {
builder()->Jump(sites->New());
}
void BreakableControlFlowBuilder::EmitJumpIfTrue(BytecodeLabels* sites) {
builder()->JumpIfTrue(sites->New());
void BreakableControlFlowBuilder::EmitJumpIfTrue(
BytecodeArrayBuilder::ToBooleanMode mode, BytecodeLabels* sites) {
builder()->JumpIfTrue(mode, sites->New());
}
void BreakableControlFlowBuilder::EmitJumpIfFalse(BytecodeLabels* sites) {
builder()->JumpIfFalse(sites->New());
void BreakableControlFlowBuilder::EmitJumpIfFalse(
BytecodeArrayBuilder::ToBooleanMode mode, BytecodeLabels* sites) {
builder()->JumpIfFalse(mode, sites->New());
}
void BreakableControlFlowBuilder::EmitJumpIfUndefined(BytecodeLabels* sites) {
......@@ -38,7 +40,6 @@ void BreakableControlFlowBuilder::EmitJumpIfNull(BytecodeLabels* sites) {
builder()->JumpIfNull(sites->New());
}
void BlockBuilder::EndBlock() {
builder()->Bind(&block_end_);
BindBreakTarget();
......
......@@ -44,8 +44,12 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder
// Inserts a jump to an unbound label that is patched when the corresponding
// BindBreakTarget is called.
void Break() { EmitJump(&break_labels_); }
void BreakIfTrue() { EmitJumpIfTrue(&break_labels_); }
void BreakIfFalse() { EmitJumpIfFalse(&break_labels_); }
void BreakIfTrue(BytecodeArrayBuilder::ToBooleanMode mode) {
EmitJumpIfTrue(mode, &break_labels_);
}
void BreakIfFalse(BytecodeArrayBuilder::ToBooleanMode mode) {
EmitJumpIfFalse(mode, &break_labels_);
}
void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); }
void BreakIfNull() { EmitJumpIfNull(&break_labels_); }
......@@ -53,8 +57,10 @@ class V8_EXPORT_PRIVATE BreakableControlFlowBuilder
protected:
void EmitJump(BytecodeLabels* labels);
void EmitJumpIfTrue(BytecodeLabels* labels);
void EmitJumpIfFalse(BytecodeLabels* labels);
void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,
BytecodeLabels* labels);
void EmitJumpIfFalse(BytecodeArrayBuilder::ToBooleanMode mode,
BytecodeLabels* labels);
void EmitJumpIfUndefined(BytecodeLabels* labels);
void EmitJumpIfNull(BytecodeLabels* labels);
......@@ -96,7 +102,6 @@ class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
// Inserts a jump to an unbound label that is patched when BindContinueTarget
// is called.
void Continue() { EmitJump(&continue_labels_); }
void ContinueIfTrue() { EmitJumpIfTrue(&continue_labels_); }
void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); }
......@@ -126,9 +131,11 @@ class V8_EXPORT_PRIVATE SwitchBuilder final
void SetCaseTarget(int index);
// This method is called when visiting case comparison operation for |index|.
// Inserts a JumpIfTrue to a unbound label that is patched when the
// corresponding SetCaseTarget is called.
void Case(int index) { builder()->JumpIfTrue(&case_sites_.at(index)); }
// Inserts a JumpIfTrue with ToBooleanMode |mode| to a unbound label that is
// patched when the corresponding SetCaseTarget is called.
void Case(BytecodeArrayBuilder::ToBooleanMode mode, int index) {
builder()->JumpIfTrue(mode, &case_sites_.at(index));
}
// This method is called when all cases comparisons have been emitted if there
// is a default case statement. Inserts a Jump to a unbound label that is
......
......@@ -79,8 +79,6 @@ const char* PeepholeActionTableWriter::kNamespaceElements[] = {"v8", "internal",
// static
PeepholeActionAndData PeepholeActionTableWriter::LookupActionAndData(
Bytecode last, Bytecode current) {
// ToName bytecodes can be replaced by Star with the same output register if
// the value in the accumulator is already a name.
if (current == Bytecode::kToName && Bytecodes::PutsNameInAccumulator(last)) {
return {PeepholeAction::kChangeBytecodeAction, Bytecode::kStar};
}
......@@ -122,16 +120,6 @@ PeepholeActionAndData PeepholeActionTableWriter::LookupActionAndData(
// TODO(rmcilroy): Add elide for consecutive mov to and from the same
// register.
// Remove ToBoolean coercion from conditional jumps where possible.
if (Bytecodes::WritesBooleanToAccumulator(last)) {
if (Bytecodes::IsJumpIfToBoolean(current)) {
return {PeepholeAction::kChangeJumpBytecodeAction,
Bytecodes::GetJumpWithoutToBoolean(current)};
} else if (current == Bytecode::kToBooleanLogicalNot) {
return {PeepholeAction::kChangeBytecodeAction, Bytecode::kLogicalNot};
}
}
// Fuse LdaSmi followed by binary op to produce binary op with a
// immediate integer argument. This savaes on dispatches and size.
if (last == Bytecode::kLdaSmi) {
......
......@@ -155,7 +155,7 @@ bytecodes: [
B(LdaConstant), U8(4),
B(TestEqualStrictNoFeedback), R(7),
B(Mov), R(4), R(6),
B(JumpIfToBooleanFalse), U8(7),
B(JumpIfFalse), U8(7),
B(CallRuntime), U16(Runtime::kThrowStaticPrototypeError), R(0), U8(0),
B(CreateClosure), U8(5), U8(4), U8(2),
B(Star), R(8),
......
......@@ -143,7 +143,7 @@ bytecodes: [
/* 42 S> */ B(LdaZero),
B(Star), R(0),
/* 45 S> */ B(TestUndetectable),
/* 57 E> */ B(JumpIfFalse), U8(6),
B(JumpIfFalse), U8(6),
B(LdaSmi), I8(1),
B(Jump), U8(4),
B(LdaSmi), I8(2),
......@@ -244,7 +244,7 @@ bytecodes: [
/* 42 S> */ B(LdaZero),
B(Star), R(0),
/* 45 S> */ B(TestUndetectable),
/* 51 E> */ B(JumpIfTrue), U8(5),
B(JumpIfTrue), U8(5),
/* 69 S> */ B(LdaSmi), I8(1),
/* 81 S> */ B(Return),
B(LdaUndefined),
......
......@@ -23,7 +23,7 @@ bytecodes: [
B(Star), R(1),
/* 67 S> */ B(Ldar), R(0),
B(TestUndetectable),
/* 77 E> */ B(JumpIfFalse), U8(6),
B(JumpIfFalse), U8(6),
/* 88 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 97 S> */ B(Ldar), R(1),
......@@ -53,7 +53,7 @@ bytecodes: [
B(Star), R(1),
/* 67 S> */ B(Ldar), R(0),
B(TestUndetectable),
/* 77 E> */ B(JumpIfFalse), U8(6),
B(JumpIfFalse), U8(6),
/* 93 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 102 S> */ B(Ldar), R(1),
......@@ -83,7 +83,7 @@ bytecodes: [
B(Star), R(1),
/* 67 S> */ B(Ldar), R(0),
B(TestUndetectable),
/* 77 E> */ B(JumpIfTrue), U8(6),
B(JumpIfTrue), U8(6),
/* 88 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 97 S> */ B(Ldar), R(1),
......@@ -113,7 +113,7 @@ bytecodes: [
B(Star), R(1),
/* 67 S> */ B(Ldar), R(0),
B(TestUndetectable),
/* 77 E> */ B(JumpIfTrue), U8(6),
B(JumpIfTrue), U8(6),
/* 93 S> */ B(LdaSmi), I8(20),
B(Star), R(1),
/* 102 S> */ B(Ldar), R(1),
......
......@@ -24,7 +24,7 @@ bytecodes: [
/* 45 S> */ B(LdaSmi), I8(1),
B(TestEqualStrict), R(1), U8(2),
B(Mov), R(0), R(2),
B(JumpIfToBooleanTrue), U8(11),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(2), U8(3),
B(JumpIfTrue), U8(7),
......@@ -60,7 +60,7 @@ bytecodes: [
/* 45 S> */ B(LdaSmi), I8(1),
B(TestEqualStrict), R(1), U8(2),
B(Mov), R(0), R(2),
B(JumpIfToBooleanTrue), U8(11),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(2), U8(3),
B(JumpIfTrue), U8(10),
......@@ -98,7 +98,7 @@ bytecodes: [
/* 45 S> */ B(LdaSmi), I8(1),
B(TestEqualStrict), R(1), U8(2),
B(Mov), R(0), R(2),
B(JumpIfToBooleanTrue), U8(11),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(2), U8(3),
B(JumpIfTrue), U8(8),
......@@ -136,7 +136,7 @@ bytecodes: [
/* 45 S> */ B(LdaSmi), I8(2),
B(TestEqualStrict), R(1), U8(2),
B(Mov), R(0), R(2),
B(JumpIfToBooleanTrue), U8(11),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(3),
B(TestEqualStrict), R(2), U8(3),
B(JumpIfTrue), U8(6),
......@@ -175,7 +175,7 @@ bytecodes: [
/* 45 S> */ B(LdaSmi), I8(2),
B(TestEqualStrict), R(1), U8(2),
B(Mov), R(1), R(2),
B(JumpIfToBooleanTrue), U8(11),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(3),
B(TestEqualStrict), R(2), U8(3),
B(JumpIfTrue), U8(10),
......@@ -216,7 +216,7 @@ bytecodes: [
/* 45 S> */ B(TypeOf),
B(TestEqualStrict), R(1), U8(2),
B(Mov), R(0), R(2),
B(JumpIfToBooleanTrue), U8(4),
B(JumpIfTrue), U8(4),
B(Jump), U8(8),
/* 74 S> */ B(LdaSmi), I8(1),
B(Star), R(0),
......@@ -318,7 +318,7 @@ bytecodes: [
/* 45 S> */ B(LdaSmi), I8(1),
B(TestEqualStrict), R(1), U8(2),
B(Mov), R(0), R(2),
B(JumpIfToBooleanTrue), U8(11),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(2), U8(3),
B(JumpIfTrueConstant), U8(0),
......@@ -488,7 +488,7 @@ bytecodes: [
/* 45 S> */ B(LdaSmi), I8(1),
B(TestEqualStrict), R(2), U8(5),
B(Mov), R(0), R(3),
B(JumpIfToBooleanTrue), U8(11),
B(JumpIfTrue), U8(11),
B(LdaSmi), I8(2),
B(TestEqualStrict), R(3), U8(6),
B(JumpIfTrue), U8(34),
......@@ -498,7 +498,7 @@ bytecodes: [
/* 70 S> */ B(LdaSmi), I8(2),
B(TestEqualStrict), R(1), U8(3),
B(Mov), R(1), R(4),
B(JumpIfToBooleanTrue), U8(4),
B(JumpIfTrue), U8(4),
B(Jump), U8(8),
/* 101 S> */ B(LdaSmi), I8(1),
B(Star), R(0),
......
......@@ -27,6 +27,8 @@ static int GetIndex(FeedbackSlot slot) {
return FeedbackVector::GetIndex(slot);
}
using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
TEST(InterpreterReturn) {
HandleAndZoneScope handles;
Isolate* isolate = handles.main_isolate();
......@@ -1510,19 +1512,19 @@ TEST(InterpreterConditionalJumps) {
builder.LoadLiteral(Smi::kZero)
.StoreAccumulatorInRegister(reg)
.LoadFalse()
.JumpIfFalse(&label[0]);
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &label[0]);
IncrementRegister(builder, reg, 1024, scratch, GetIndex(slot))
.Bind(&label[0])
.LoadTrue()
.JumpIfFalse(&done);
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done);
IncrementRegister(builder, reg, 1, scratch, GetIndex(slot1))
.LoadTrue()
.JumpIfTrue(&label[1]);
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &label[1]);
IncrementRegister(builder, reg, 2048, scratch, GetIndex(slot2))
.Bind(&label[1]);
IncrementRegister(builder, reg, 2, scratch, GetIndex(slot3))
.LoadFalse()
.JumpIfTrue(&done1);
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &done1);
IncrementRegister(builder, reg, 4, scratch, GetIndex(slot4))
.LoadAccumulatorWithRegister(reg)
.Bind(&done)
......@@ -1560,19 +1562,19 @@ TEST(InterpreterConditionalJumps2) {
builder.LoadLiteral(Smi::kZero)
.StoreAccumulatorInRegister(reg)
.LoadFalse()
.JumpIfFalse(&label[0]);
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &label[0]);
IncrementRegister(builder, reg, 1024, scratch, GetIndex(slot))
.Bind(&label[0])
.LoadTrue()
.JumpIfFalse(&done);
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &done);
IncrementRegister(builder, reg, 1, scratch, GetIndex(slot1))
.LoadTrue()
.JumpIfTrue(&label[1]);
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &label[1]);
IncrementRegister(builder, reg, 2048, scratch, GetIndex(slot2))
.Bind(&label[1]);
IncrementRegister(builder, reg, 2, scratch, GetIndex(slot3))
.LoadFalse()
.JumpIfTrue(&done1);
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &done1);
IncrementRegister(builder, reg, 4, scratch, GetIndex(slot4))
.LoadAccumulatorWithRegister(reg)
.Bind(&done)
......@@ -2203,7 +2205,7 @@ TEST(InterpreterUnaryNot) {
Register r0(0);
builder.LoadFalse();
for (size_t j = 0; j < i; j++) {
builder.LogicalNot();
builder.LogicalNot(ToBooleanMode::kAlreadyBoolean);
}
builder.Return();
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
......@@ -2241,7 +2243,7 @@ TEST(InterpreterUnaryNotNonBoolean) {
Register r0(0);
builder.LoadLiteral(object_type_tuples[i].first);
builder.LogicalNot();
builder.LogicalNot(ToBooleanMode::kConvertToBoolean);
builder.Return();
ast_factory.Internalize(isolate);
Handle<BytecodeArray> bytecode_array = builder.ToBytecodeArray(isolate);
......
......@@ -17,6 +17,8 @@ namespace v8 {
namespace internal {
namespace compiler {
using ToBooleanMode = interpreter::BytecodeArrayBuilder::ToBooleanMode;
class BytecodeAnalysisTest : public TestWithIsolateAndZone {
public:
BytecodeAnalysisTest() {}
......@@ -155,7 +157,7 @@ TEST_F(BytecodeAnalysisTest, DiamondLoad) {
interpreter::BytecodeLabel ld1_label;
interpreter::BytecodeLabel end_label;
builder.JumpIfTrue(&ld1_label);
builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &ld1_label);
expected_liveness.emplace_back("LLLL", "LLL.");
builder.LoadAccumulatorWithRegister(reg_0);
......@@ -195,7 +197,7 @@ TEST_F(BytecodeAnalysisTest, DiamondLookupsAndBinds) {
builder.StoreAccumulatorInRegister(reg_0);
expected_liveness.emplace_back(".LLL", "LLLL");
builder.JumpIfTrue(&ld1_label);
builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &ld1_label);
expected_liveness.emplace_back("LLLL", "LLL.");
{
......@@ -242,7 +244,8 @@ TEST_F(BytecodeAnalysisTest, SimpleLoop) {
interpreter::LoopBuilder loop_builder(&builder);
loop_builder.LoopHeader();
{
builder.JumpIfTrue(loop_builder.break_labels()->New());
builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
loop_builder.break_labels()->New());
expected_liveness.emplace_back("L.LL", "L.L.");
builder.LoadAccumulatorWithRegister(reg_0);
......@@ -327,12 +330,13 @@ TEST_F(BytecodeAnalysisTest, DiamondInLoop) {
interpreter::LoopBuilder loop_builder(&builder);
loop_builder.LoopHeader();
{
builder.JumpIfTrue(loop_builder.break_labels()->New());
builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
loop_builder.break_labels()->New());
expected_liveness.emplace_back("L..L", "L..L");
interpreter::BytecodeLabel ld1_label;
interpreter::BytecodeLabel end_label;
builder.JumpIfTrue(&ld1_label);
builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &ld1_label);
expected_liveness.emplace_back("L..L", "L..L");
{
......@@ -381,7 +385,8 @@ TEST_F(BytecodeAnalysisTest, KillingLoopInsideLoop) {
builder.LoadAccumulatorWithRegister(reg_1);
expected_liveness.emplace_back(".L..", ".L.L");
builder.JumpIfTrue(loop_builder.break_labels()->New());
builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
loop_builder.break_labels()->New());
expected_liveness.emplace_back(".L.L", ".L.L");
interpreter::LoopBuilder inner_loop_builder(&builder);
......@@ -390,7 +395,8 @@ TEST_F(BytecodeAnalysisTest, KillingLoopInsideLoop) {
builder.StoreAccumulatorInRegister(reg_0);
expected_liveness.emplace_back(".L.L", "LL.L");
builder.JumpIfTrue(inner_loop_builder.break_labels()->New());
builder.JumpIfTrue(ToBooleanMode::kConvertToBoolean,
inner_loop_builder.break_labels()->New());
expected_liveness.emplace_back("LL.L", "LL.L");
inner_loop_builder.BindContinueTarget();
......
......@@ -22,6 +22,8 @@ class BytecodeArrayBuilderTest : public TestWithIsolateAndZone {
~BytecodeArrayBuilderTest() override {}
};
using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
CanonicalHandleScope canonical(isolate());
BytecodeArrayBuilder builder(isolate(), zone(), 0, 1, 131);
......@@ -194,9 +196,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.CountOperation(Token::Value::SUB, 1);
// Emit unary operator invocations.
builder
.LogicalNot() // ToBooleanLogicalNot
.LogicalNot() // non-ToBoolean LogicalNot
builder.LogicalNot(ToBooleanMode::kConvertToBoolean)
.LogicalNot(ToBooleanMode::kAlreadyBoolean)
.TypeOf();
// Emit delete
......@@ -241,7 +242,8 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
// Short jumps with Imm8 operands
{
BytecodeLabel start, after_jump1, after_jump2, after_jump3, after_jump4,
after_jump5, after_jump6, after_jump7;
after_jump5, after_jump6, after_jump7, after_jump8, after_jump9,
after_jump10, after_jump11;
builder.Bind(&start)
.Jump(&after_jump1)
.Bind(&after_jump1)
......@@ -257,6 +259,14 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.Bind(&after_jump6)
.JumpIfJSReceiver(&after_jump7)
.Bind(&after_jump7)
.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &after_jump8)
.Bind(&after_jump8)
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &after_jump9)
.Bind(&after_jump9)
.JumpIfFalse(ToBooleanMode::kConvertToBoolean, &after_jump10)
.Bind(&after_jump10)
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &after_jump11)
.Bind(&after_jump11)
.JumpLoop(&start, 0);
}
......@@ -266,14 +276,10 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
BytecodeLabel after_jump;
builder.Jump(&end[0])
.Bind(&after_jump)
.LoadTrue()
.JumpIfTrue(&end[1])
.LoadTrue()
.JumpIfFalse(&end[2])
.LoadLiteral(Smi::kZero)
.JumpIfTrue(&end[3])
.LoadLiteral(Smi::kZero)
.JumpIfFalse(&end[4])
.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &end[1])
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &end[2])
.JumpIfFalse(ToBooleanMode::kConvertToBoolean, &end[3])
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &end[4])
.JumpIfNull(&end[5])
.JumpIfNotNull(&end[6])
.JumpIfUndefined(&end[7])
......@@ -283,30 +289,6 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
.JumpIfJSReceiver(&end[10]);
}
// Perform an operation that returns boolean value to
// generate JumpIfTrue/False
{
BytecodeLabel after_jump1, after_jump2;
builder.CompareOperation(Token::Value::EQ, reg, 1)
.JumpIfTrue(&after_jump1)
.Bind(&after_jump1)
.CompareOperation(Token::Value::EQ, reg, 2)
.JumpIfFalse(&after_jump2)
.Bind(&after_jump2);
}
// Perform an operation that returns a non-boolean operation to
// generate JumpIfToBooleanTrue/False.
{
BytecodeLabel after_jump1, after_jump2;
builder.BinaryOperation(Token::Value::ADD, reg, 1)
.JumpIfTrue(&after_jump1)
.Bind(&after_jump1)
.BinaryOperation(Token::Value::ADD, reg, 2)
.JumpIfFalse(&after_jump2)
.Bind(&after_jump2);
}
// Emit set pending message bytecode.
builder.SetPendingMessage();
......@@ -439,12 +421,6 @@ TEST_F(BytecodeArrayBuilderTest, AllBytecodesGenerated) {
if (!FLAG_ignition_peephole) {
// Insert entries for bytecodes only emitted by peephole optimizer.
scorecard[Bytecodes::ToByte(Bytecode::kLogicalNot)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJump)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJumpIfTrue)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJumpIfFalse)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJumpIfTrueConstant)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kJumpIfFalseConstant)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kAddSmi)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kSubSmi)] = 1;
scorecard[Bytecodes::ToByte(Bytecode::kBitwiseAndSmi)] = 1;
......@@ -573,13 +549,13 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
builder.Jump(&near0)
.Bind(&after_jump0)
.CompareOperation(Token::Value::EQ, reg, 1)
.JumpIfTrue(&near1)
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &near1)
.CompareOperation(Token::Value::EQ, reg, 2)
.JumpIfFalse(&near2)
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &near2)
.BinaryOperation(Token::Value::ADD, reg, 1)
.JumpIfTrue(&near3)
.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &near3)
.BinaryOperation(Token::Value::ADD, reg, 2)
.JumpIfFalse(&near4)
.JumpIfFalse(ToBooleanMode::kConvertToBoolean, &near4)
.Bind(&near0)
.Bind(&near1)
.Bind(&near2)
......@@ -588,13 +564,13 @@ TEST_F(BytecodeArrayBuilderTest, ForwardJumps) {
.Jump(&far0)
.Bind(&after_jump1)
.CompareOperation(Token::Value::EQ, reg, 3)
.JumpIfTrue(&far1)
.JumpIfTrue(ToBooleanMode::kAlreadyBoolean, &far1)
.CompareOperation(Token::Value::EQ, reg, 4)
.JumpIfFalse(&far2)
.JumpIfFalse(ToBooleanMode::kAlreadyBoolean, &far2)
.BinaryOperation(Token::Value::ADD, reg, 3)
.JumpIfTrue(&far3)
.JumpIfTrue(ToBooleanMode::kConvertToBoolean, &far3)
.BinaryOperation(Token::Value::ADD, reg, 4)
.JumpIfFalse(&far4);
.JumpIfFalse(ToBooleanMode::kConvertToBoolean, &far4);
for (int i = 0; i < kFarJumpDistance - 22; i++) {
builder.Debugger();
}
......
......@@ -128,56 +128,6 @@ TEST_F(BytecodePeepholeOptimizerTest, KeepStatementNop) {
CHECK_EQ(add, last_written());
}
// Tests covering BytecodePeepholeOptimizer::UpdateCurrentBytecode().
TEST_F(BytecodePeepholeOptimizerTest, KeepJumpIfToBooleanTrue) {
BytecodeNode first(Bytecode::kLdaNull);
BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3);
BytecodeLabel label;
optimizer()->Write(&first);
CHECK_EQ(write_count(), 0);
optimizer()->WriteJump(&second, &label);
CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written(), second);
}
TEST_F(BytecodePeepholeOptimizerTest, ElideJumpIfToBooleanTrue) {
BytecodeNode first(Bytecode::kLdaTrue);
BytecodeNode second(Bytecode::kJumpIfToBooleanTrue, 3);
BytecodeLabel label;
optimizer()->Write(&first);
CHECK_EQ(write_count(), 0);
optimizer()->WriteJump(&second, &label);
CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written(), second);
}
TEST_F(BytecodePeepholeOptimizerTest, KeepToBooleanLogicalNot) {
BytecodeNode first(Bytecode::kLdaNull);
BytecodeNode second(Bytecode::kToBooleanLogicalNot);
optimizer()->Write(&first);
CHECK_EQ(write_count(), 0);
optimizer()->Write(&second);
CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first);
Flush();
CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written(), second);
}
TEST_F(BytecodePeepholeOptimizerTest, ElideToBooleanLogicalNot) {
BytecodeNode first(Bytecode::kLdaTrue);
BytecodeNode second(Bytecode::kToBooleanLogicalNot);
optimizer()->Write(&first);
CHECK_EQ(write_count(), 0);
optimizer()->Write(&second);
CHECK_EQ(write_count(), 1);
CHECK_EQ(last_written(), first);
Flush();
CHECK_EQ(write_count(), 2);
CHECK_EQ(last_written().bytecode(), Bytecode::kLogicalNot);
}
// Tests covering BytecodePeepholeOptimizer::CanElideCurrent().
TEST_F(BytecodePeepholeOptimizerTest, StarRxLdarRy) {
......
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