Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/interpreter/bytecode-peephole-optimizer.h" | 5 #include "src/interpreter/bytecode-peephole-optimizer.h" |
| 6 | 6 |
| 7 #include "src/interpreter/constant-array-builder.h" | 7 #include "src/interpreter/constant-array-builder.h" |
| 8 #include "src/objects-inl.h" | 8 #include "src/objects-inl.h" |
| 9 #include "src/objects.h" | 9 #include "src/objects.h" |
| 10 | 10 |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 87 } | 87 } |
| 88 | 88 |
| 89 bool BytecodePeepholeOptimizer::LastBytecodePutsNameInAccumulator() const { | 89 bool BytecodePeepholeOptimizer::LastBytecodePutsNameInAccumulator() const { |
| 90 DCHECK(LastIsValid()); | 90 DCHECK(LastIsValid()); |
| 91 return (last_.bytecode() == Bytecode::kTypeOf || | 91 return (last_.bytecode() == Bytecode::kTypeOf || |
| 92 last_.bytecode() == Bytecode::kToName || | 92 last_.bytecode() == Bytecode::kToName || |
| 93 (last_.bytecode() == Bytecode::kLdaConstant && | 93 (last_.bytecode() == Bytecode::kLdaConstant && |
| 94 GetConstantForIndexOperand(&last_, 0)->IsName())); | 94 GetConstantForIndexOperand(&last_, 0)->IsName())); |
| 95 } | 95 } |
| 96 | 96 |
| 97 void BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes( | 97 void BytecodePeepholeOptimizer::TryToRemoveLastExpressionPosition( |
| 98 BytecodeNode* current) { | 98 const BytecodeNode* const current) { |
| 99 if (Bytecodes::IsJumpIfToBoolean(current->bytecode()) && | |
| 100 Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) { | |
| 101 // Conditional jumps with boolean conditions are emitted in | |
| 102 // ToBoolean form by the bytecode array builder, | |
| 103 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean element | |
| 104 // can be removed if the previous bytecode put a boolean value in | |
| 105 // the accumulator. | |
| 106 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode()); | |
| 107 current->set_bytecode(jump, current->operand(0), current->operand_scale()); | |
| 108 } else if (current->bytecode() == Bytecode::kToBooleanLogicalNot && | |
| 109 Bytecodes::WritesBooleanToAccumulator(last_.bytecode())) { | |
| 110 // Logical-nots are emitted in ToBoolean form by the bytecode array | |
| 111 // builder, The ToBoolean element can be removed if the previous bytecode | |
| 112 // put a boolean value in the accumulator. | |
| 113 current->set_bytecode(Bytecode::kLogicalNot); | |
| 114 } | |
| 115 | |
| 116 if (current->source_info().is_statement() && | 99 if (current->source_info().is_statement() && |
| 117 last_.source_info().is_expression() && | 100 last_.source_info().is_expression() && |
| 118 Bytecodes::IsWithoutExternalSideEffects(last_.bytecode())) { | 101 Bytecodes::IsWithoutExternalSideEffects(last_.bytecode())) { |
| 119 // The last bytecode has been marked as expression. It has no | 102 // The last bytecode has been marked as expression. It has no |
| 120 // external effects so can't throw and the current bytecode is a | 103 // external effects so can't throw and the current bytecode is a |
| 121 // source position. Remove the expression position on the last | 104 // source position. Remove the expression position on the last |
| 122 // bytecode to open up potential peephole optimizations and to | 105 // bytecode to open up potential peephole optimizations and to |
| 123 // save the memory and perf cost of storing the unneeded | 106 // save the memory and perf cost of storing the unneeded |
| 124 // expression position. | 107 // expression position. |
| 125 last_.source_info().set_invalid(); | 108 last_.source_info().set_invalid(); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 178 // to keep the check here simple. | 161 // to keep the check here simple. |
| 179 // | 162 // |
| 180 // In rare cases, bytecode generation produces consecutive bytecodes | 163 // In rare cases, bytecode generation produces consecutive bytecodes |
| 181 // with the same expression positions. In principle, the latter of | 164 // with the same expression positions. In principle, the latter of |
| 182 // these can be elided, but would make this function more expensive. | 165 // these can be elided, but would make this function more expensive. |
| 183 // | 166 // |
| 184 return (!last_.source_info().is_valid() || | 167 return (!last_.source_info().is_valid() || |
| 185 !current->source_info().is_valid()); | 168 !current->source_info().is_valid()); |
| 186 } | 169 } |
| 187 | 170 |
| 171 namespace { | |
|
rmcilroy
2016/05/24 14:00:11
nit - newline after {
oth
2016/05/24 15:07:14
Done.
| |
| 172 void TransformLdaStarToLdrLdar(Bytecode new_bytecode, BytecodeNode* const last, | |
| 173 BytecodeNode* const current) { | |
| 174 DCHECK_EQ(current->bytecode(), Bytecodes::kStar); | |
| 175 // | |
| 176 // An example transformation here would be: | |
| 177 // | |
| 178 // LdaGlobal i0, i1 ____\ LdrGlobal i0, i1, R | |
| 179 // Star R ====/ Ldar R | |
| 180 // | |
| 181 // which loads a global value into both a register and the | |
| 182 // accumulator. However, in the second form the Ldar can often be | |
| 183 // peephole optimized away unlike the Star in the first form. | |
| 184 // | |
| 185 last->Transform(new_bytecode, current->operand(0), current->operand_scale()); | |
| 186 current->set_bytecode(Bytecode::kLdar, current->operand(0), | |
| 187 current->operand_scale()); | |
| 188 | |
| 189 // If there was a source position on |current| transfer it to the | |
| 190 // updated |last| to maintain the debugger's causal view. ie. if an | |
| 191 // expression position LdrGlobal is the bytecode that could throw | |
| 192 // and if a statement position it needs to be placed before the | |
| 193 // store to R occurs. | |
| 194 last->source_info().Update(current->source_info()); | |
| 195 current->source_info().set_invalid(); | |
| 196 } | |
| 197 } // namespace | |
|
rmcilroy
2016/05/24 14:00:11
nit - newline above
oth
2016/05/24 15:07:15
Done.
| |
| 198 | |
| 199 bool BytecodePeepholeOptimizer::ChangeLdaToLdr(BytecodeNode* const current) { | |
| 200 if (current->bytecode() == Bytecode::kStar) { | |
| 201 switch (last_.bytecode()) { | |
| 202 case Bytecode::kLoadIC: | |
| 203 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current); | |
| 204 return true; | |
| 205 case Bytecode::kKeyedLoadIC: | |
| 206 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current); | |
| 207 return true; | |
| 208 case Bytecode::kLdaGlobal: | |
| 209 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current); | |
| 210 return true; | |
| 211 case Bytecode::kLdaContextSlot: | |
| 212 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current); | |
| 213 return true; | |
| 214 case Bytecode::kLdaUndefined: | |
| 215 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current); | |
| 216 return true; | |
| 217 default: | |
| 218 break; | |
| 219 } | |
| 220 } | |
| 221 return false; | |
| 222 } | |
| 223 | |
| 224 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump( | |
| 225 BytecodeNode* const current) { | |
| 226 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) && | |
| 227 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); | |
| 228 if (can_remove) { | |
| 229 // Conditional jumps with boolean conditions are emiitted in | |
| 230 // ToBoolean form by the bytecode array builder, | |
| 231 // i.e. JumpIfToBooleanTrue rather JumpIfTrue. The ToBoolean | |
| 232 // element can be removed if the previous bytecode put a boolean | |
| 233 // value in the accumulator. | |
| 234 Bytecode jump = Bytecodes::GetJumpWithoutToBoolean(current->bytecode()); | |
| 235 current->set_bytecode(jump, current->operand(0), current->operand_scale()); | |
| 236 } | |
| 237 return can_remove; | |
| 238 } | |
| 239 | |
| 240 bool BytecodePeepholeOptimizer::RemoveToBooleanFromLogicalNot( | |
| 241 BytecodeNode* const current) { | |
| 242 bool can_remove = current->bytecode() == Bytecode::kToBooleanLogicalNot && | |
| 243 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); | |
| 244 if (can_remove) { | |
| 245 // Logical-nots are emitted in ToBoolean form by the bytecode array | |
| 246 // builder, The ToBoolean element can be removed if the previous bytecode | |
| 247 // put a boolean value in the accumulator. | |
| 248 current->set_bytecode(Bytecode::kLogicalNot); | |
| 249 } | |
| 250 return can_remove; | |
| 251 } | |
| 252 | |
| 253 bool BytecodePeepholeOptimizer::UpdateLastAndCurrentBytecodes( | |
| 254 BytecodeNode* const current) { | |
| 255 return RemoveToBooleanFromJump(current) || | |
| 256 RemoveToBooleanFromLogicalNot(current) || ChangeLdaToLdr(current); | |
| 257 } | |
| 258 | |
| 188 bool BytecodePeepholeOptimizer::CanElideLast( | 259 bool BytecodePeepholeOptimizer::CanElideLast( |
| 189 const BytecodeNode* const current) const { | 260 const BytecodeNode* const current) const { |
| 190 if (!last_is_discardable_) { | 261 if (!last_is_discardable_) { |
| 191 return false; | 262 return false; |
| 192 } | 263 } |
| 193 | 264 |
| 194 if (last_.bytecode() == Bytecode::kNop) { | 265 if (last_.bytecode() == Bytecode::kNop) { |
| 195 // Nop are placeholders for holding source position information. | 266 // Nop are placeholders for holding source position information. |
| 196 return true; | 267 return true; |
| 197 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && | 268 } else if (Bytecodes::IsAccumulatorLoadWithoutEffects(current->bytecode()) && |
| 198 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { | 269 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { |
| 199 // The accumulator is invisible to the debugger. If there is a sequence of | 270 // The accumulator is invisible to the debugger. If there is a sequence of |
| 200 // consecutive accumulator loads (that don't have side effects) then only | 271 // consecutive accumulator loads (that don't have side effects) then only |
| 201 // the final load is potentially visible. | 272 // the final load is potentially visible. |
| 202 return true; | 273 return true; |
| 274 } else if (Bytecodes::GetAccumulatorUse(current->bytecode()) == | |
| 275 AccumulatorUse::kWrite && | |
| 276 Bytecodes::IsAccumulatorLoadWithoutEffects(last_.bytecode())) { | |
| 277 // The current instruction clobbers the accumulator without reading it. The | |
| 278 // load in the last instruction can be elided as it has no effect. | |
| 279 return true; | |
| 203 } else { | 280 } else { |
| 204 return false; | 281 return false; |
| 205 } | 282 } |
| 206 } | 283 } |
| 207 | 284 |
| 208 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { | 285 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { |
| 209 UpdateLastAndCurrentBytecodes(current); | 286 TryToRemoveLastExpressionPosition(current); |
| 287 | |
| 288 if (UpdateLastAndCurrentBytecodes(current)) { | |
| 289 return current; | |
| 290 } | |
| 291 | |
| 210 if (CanElideCurrent(current)) { | 292 if (CanElideCurrent(current)) { |
| 211 if (current->source_info().is_valid()) { | 293 if (current->source_info().is_valid()) { |
| 294 // Preserve the source information by replacing the current bytecode | |
| 295 // with a no op bytecode. | |
| 212 current->set_bytecode(Bytecode::kNop); | 296 current->set_bytecode(Bytecode::kNop); |
| 213 } else { | 297 } else { |
| 214 current = nullptr; | 298 current = nullptr; |
| 215 } | 299 } |
| 216 } else if (CanElideLast(current) && | 300 return current; |
| 217 CanElideLastBasedOnSourcePosition(current)) { | 301 } |
| 302 | |
| 303 if (CanElideLast(current) && CanElideLastBasedOnSourcePosition(current)) { | |
| 218 current->source_info().Update(last_.source_info()); | 304 current->source_info().Update(last_.source_info()); |
| 219 InvalidateLast(); | 305 InvalidateLast(); |
|
rmcilroy
2016/05/24 14:00:11
Please add "return current" here too ensure we don
oth
2016/05/24 15:07:15
Done.
| |
| 220 } | 306 } |
| 221 return current; | 307 return current; |
| 222 } | 308 } |
| 223 | 309 |
| 224 } // namespace interpreter | 310 } // namespace interpreter |
| 225 } // namespace internal | 311 } // namespace internal |
| 226 } // namespace v8 | 312 } // namespace v8 |
| OLD | NEW |