Index: src/interpreter/bytecode-peephole-optimizer.cc |
diff --git a/src/interpreter/bytecode-peephole-optimizer.cc b/src/interpreter/bytecode-peephole-optimizer.cc |
index 803fc23089927faf47fe893deb178dd479265d6f..9683e301e8b5a345c708183d652354479271afa7 100644 |
--- a/src/interpreter/bytecode-peephole-optimizer.cc |
+++ b/src/interpreter/bytecode-peephole-optimizer.cc |
@@ -94,7 +94,8 @@ bool BytecodePeepholeOptimizer::LastBytecodePutsNameInAccumulator() const { |
GetConstantForIndexOperand(&last_, 0)->IsName())); |
} |
-void BytecodePeepholeOptimizer::UpdateCurrentBytecode(BytecodeNode* current) { |
+void BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes( |
+ BytecodeNode* current) { |
if (Bytecodes::IsJumpIfToBoolean(current->bytecode()) && |
Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) { |
// Conditional jumps with boolean conditions are emitted in |
@@ -111,6 +112,18 @@ void BytecodePeepholeOptimizer::UpdateCurrentBytecode(BytecodeNode* current) { |
// put a boolean value in the accumulator. |
current->set_bytecode(Bytecode::kLogicalNot); |
} |
+ |
+ if (current->source_info().is_statement() && |
+ last_.source_info().is_expression() && |
+ Bytecodes::IsWithoutExternalSideEffects(last_.bytecode())) { |
+ // The last bytecode has been marked as expression. It has no |
+ // external effects so can't throw and the current bytecode is a |
+ // source position. Remove the expression position on the last |
+ // bytecode to open up potential peephole optimizations and to |
+ // save the memory and perf cost of storing the unneeded |
+ // expression position. |
+ last_.source_info().set_invalid(); |
+ } |
} |
bool BytecodePeepholeOptimizer::CanElideCurrent( |
@@ -134,6 +147,44 @@ bool BytecodePeepholeOptimizer::CanElideCurrent( |
} |
} |
+bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( |
+ const BytecodeNode* const current) const { |
+ // |
+ // The rules for allowing the elision of the last bytecode based |
+ // on source position are: |
+ // |
+ // C U R R E N T |
+ // +--------+--------+--------+ |
+ // | None | Expr | Stmt | |
+ // L +--------+--------+--------+--------+ |
+ // | None | YES | YES | YES | |
+ // A +--------+--------+--------+--------+ |
+ // | Expr | YES | MAYBE | MAYBE | |
+ // S +--------+--------+--------+--------+ |
+ // | Stmt | YES | NO | NO | |
+ // T +--------+--------+--------+--------+ |
+ // |
+ // The goal is not lose any statement positions and not lose useful |
+ // expression positions. Whenever the last bytecode is elided it's |
+ // 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. |
+ // |
+ // In rare cases, bytecode generation produces consecutive bytecodes |
+ // with the same expression positions. In principle, the latter of |
+ // these can be elided, but would make this function more expensive. |
+ // |
+ return (!last_.source_info().is_valid() || |
+ !current->source_info().is_valid()); |
+} |
+ |
bool BytecodePeepholeOptimizer::CanElideLast( |
const BytecodeNode* const current) const { |
if (!last_is_discardable_) { |
@@ -141,8 +192,7 @@ bool BytecodePeepholeOptimizer::CanElideLast( |
} |
if (last_.bytecode() == Bytecode::kNop) { |
- // Nop are placeholders for holding source position information |
- // and can be elided. |
+ // Nop are placeholders for holding source position information. |
return true; |
} else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && |
Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { |
@@ -156,18 +206,16 @@ bool BytecodePeepholeOptimizer::CanElideLast( |
} |
BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { |
- UpdateCurrentBytecode(current); |
- |
+ UpdateLastAndCurrentBytecodes(current); |
if (CanElideCurrent(current)) { |
if (current->source_info().is_valid()) { |
current->set_bytecode(Bytecode::kNop); |
} else { |
current = nullptr; |
} |
- } else if (CanElideLast(current)) { |
- if (last_.source_info().is_valid()) { |
- current->source_info().Update(last_.source_info()); |
- } |
+ } else if (CanElideLast(current) && |
+ CanElideLastBasedOnSourcePosition(current)) { |
+ current->source_info().Update(last_.source_info()); |
InvalidateLast(); |
} |
return current; |