| Index: src/interpreter/bytecode-peephole-optimizer.cc
|
| diff --git a/src/interpreter/bytecode-peephole-optimizer.cc b/src/interpreter/bytecode-peephole-optimizer.cc
|
| index 9683e301e8b5a345c708183d652354479271afa7..dc2d33b2ede6695aaac1719098e362217f595ee4 100644
|
| --- a/src/interpreter/bytecode-peephole-optimizer.cc
|
| +++ b/src/interpreter/bytecode-peephole-optimizer.cc
|
| @@ -94,25 +94,8 @@ bool BytecodePeepholeOptimizer::LastBytecodePutsNameInAccumulator() const {
|
| GetConstantForIndexOperand(&last_, 0)->IsName()));
|
| }
|
|
|
| -void BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes(
|
| - BytecodeNode* current) {
|
| - if (Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
|
| - Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) {
|
| - // Conditional jumps with boolean conditions are emitted in
|
| - // ToBoolean form by the bytecode array builder,
|
| - // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean element
|
| - // can be removed if the previous bytecode put a boolean value in
|
| - // the accumulator.
|
| - Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode());
|
| - current->set_bytecode(jump, current->operand(0), current->operand_scale());
|
| - } else if (current->bytecode() == Bytecode::kToBooleanLogicalNot &&
|
| - Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) {
|
| - // Logical-nots are emitted in ToBoolean form by the bytecode array
|
| - // builder, The ToBoolean element can be removed if the previous bytecode
|
| - // put a boolean value in the accumulator.
|
| - current->set_bytecode(Bytecode::kLogicalNot);
|
| - }
|
| -
|
| +void BytecodePeepholeOptimizer::TryToRemoveLastExpressionPosition(
|
| + const BytecodeNode* const current) {
|
| if (current->source_info().is_statement() &&
|
| last_.source_info().is_expression() &&
|
| Bytecodes::IsWithoutExternalSideEffects(last_.bytecode())) {
|
| @@ -169,13 +152,13 @@ bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition(
|
| // source position information is applied to the current node
|
| // updating it if necessary.
|
| //
|
| - //
|
| // The last bytecode can be elided for the MAYBE cases if the last
|
| // bytecode is known not to throw. If it throws, the system would
|
| // not have correct stack trace information. The appropriate check
|
| - // for this would be Bytecodes::IsWithoutExternalSideEffects(), which
|
| - // is checked in BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes()
|
| - // to keep the check here simple.
|
| + // for this would be Bytecodes::IsWithoutExternalSideEffects(),
|
| + // which is checked in
|
| + // BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes() to
|
| + // keep the check here simple.
|
| //
|
| // In rare cases, bytecode generation produces consecutive bytecodes
|
| // with the same expression positions. In principle, the latter of
|
| @@ -185,6 +168,96 @@ bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition(
|
| !current->source_info().is_valid());
|
| }
|
|
|
| +namespace {
|
| +
|
| +void TransformLdaStarToLdrLdar(Bytecode new_bytecode, BytecodeNode* const last,
|
| + BytecodeNode* const current) {
|
| + DCHECK_EQ(current->bytecode(), Bytecode::kStar);
|
| + //
|
| + // An example transformation here would be:
|
| + //
|
| + // LdaGlobal i0, i1 ____\ LdrGlobal i0, i1, R
|
| + // Star R ====/ Ldar R
|
| + //
|
| + // which loads a global value into both a register and the
|
| + // accumulator. However, in the second form the Ldar can often be
|
| + // peephole optimized away unlike the Star in the first form.
|
| + //
|
| + last->Transform(new_bytecode, current->operand(0), current->operand_scale());
|
| + current->set_bytecode(Bytecode::kLdar, current->operand(0),
|
| + current->operand_scale());
|
| +
|
| + // If there was a source position on |current| transfer it to the
|
| + // updated |last| to maintain the debugger's causal view. ie. if an
|
| + // expression position LdrGlobal is the bytecode that could throw
|
| + // and if a statement position it needs to be placed before the
|
| + // store to R occurs.
|
| + last->source_info().Update(current->source_info());
|
| + current->source_info().set_invalid();
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +bool BytecodePeepholeOptimizer::ChangeLdaToLdr(BytecodeNode* const current) {
|
| + if (current->bytecode() == Bytecode::kStar) {
|
| + switch (last_.bytecode()) {
|
| + case Bytecode::kLoadIC:
|
| + TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current);
|
| + return true;
|
| + case Bytecode::kKeyedLoadIC:
|
| + TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current);
|
| + return true;
|
| + case Bytecode::kLdaGlobal:
|
| + TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current);
|
| + return true;
|
| + case Bytecode::kLdaContextSlot:
|
| + TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current);
|
| + return true;
|
| + case Bytecode::kLdaUndefined:
|
| + TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current);
|
| + return true;
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| + return false;
|
| +}
|
| +
|
| +bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump(
|
| + BytecodeNode* const current) {
|
| + bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) &&
|
| + Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
|
| + if (can_remove) {
|
| + // Conditional jumps with boolean conditions are emiitted in
|
| + // ToBoolean form by the bytecode array builder,
|
| + // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean
|
| + // element can be removed if the previous bytecode put a boolean
|
| + // value in the accumulator.
|
| + Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode());
|
| + current->set_bytecode(jump, current->operand(0), current->operand_scale());
|
| + }
|
| + return can_remove;
|
| +}
|
| +
|
| +bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot(
|
| + BytecodeNode* const current) {
|
| + bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot &&
|
| + Bytecodes::WritesBooleanToAccumulator(last_.bytecode());
|
| + if (can_remove) {
|
| + // Logical-nots are emitted in ToBoolean form by the bytecode array
|
| + // builder, The ToBoolean element can be removed if the previous bytecode
|
| + // put a boolean value in the accumulator.
|
| + current->set_bytecode(Bytecode::kLogicalNot);
|
| + }
|
| + return can_remove;
|
| +}
|
| +
|
| +bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes(
|
| + BytecodeNode* const current) {
|
| + return RemoveToBooleanFromJump(current) ||
|
| + RemoveToBooleanFromLogicalNot(current) || ChangeLdaToLdr(current);
|
| +}
|
| +
|
| bool BytecodePeepholeOptimizer::CanElideLast(
|
| const BytecodeNode* const current) const {
|
| if (!last_is_discardable_) {
|
| @@ -200,24 +273,41 @@ bool BytecodePeepholeOptimizer::CanElideLast(
|
| // consecutive accumulator loads (that don't have side effects) then only
|
| // the final load is potentially visible.
|
| return true;
|
| + } else if (Bytecodes::GetAccumulatorUse(current->bytecode()) ==
|
| + AccumulatorUse::kWrite &&
|
| + Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) {
|
| + // The current instruction clobbers the accumulator without reading it. The
|
| + // load in the last instruction can be elided as it has no effect.
|
| + return true;
|
| } else {
|
| return false;
|
| }
|
| }
|
|
|
| BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) {
|
| - UpdateLastAndCurrentBytecodes(current);
|
| + TryToRemoveLastExpressionPosition(current);
|
| +
|
| + if (TransformLastAndCurrentBytecodes(current)) {
|
| + return current;
|
| + }
|
| +
|
| if (CanElideCurrent(current)) {
|
| if (current->source_info().is_valid()) {
|
| + // Preserve the source information by replacing the current bytecode
|
| + // with a no op bytecode.
|
| current->set_bytecode(Bytecode::kNop);
|
| } else {
|
| current = nullptr;
|
| }
|
| - } else if (CanElideLast(current) &&
|
| - CanElideLastBasedOnSourcePosition(current)) {
|
| + return current;
|
| + }
|
| +
|
| + if (CanElideLast(current) && CanElideLastBasedOnSourcePosition(current)) {
|
| current->source_info().Update(last_.source_info());
|
| InvalidateLast();
|
| + return current;
|
| }
|
| +
|
| return current;
|
| }
|
|
|
|
|