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 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 119 // of back-to-back Ldar and Star bytecodes with the same operand. | 119 // of back-to-back Ldar and Star bytecodes with the same operand. |
| 120 return true; | 120 return true; |
| 121 } else if (current->bytecode() == Bytecode::kToName && | 121 } else if (current->bytecode() == Bytecode::kToName && |
| 122 LastBytecodePutsNameInAccumulator()) { | 122 LastBytecodePutsNameInAccumulator()) { |
| 123 // If the previous bytecode ensured a name was in the accumulator, | 123 // If the previous bytecode ensured a name was in the accumulator, |
| 124 // the type coercion ToName() can be elided. | 124 // the type coercion ToName() can be elided. |
| 125 return true; | 125 return true; |
| 126 } else { | 126 } else { |
| 127 // Additional candidates for eliding current: | 127 // Additional candidates for eliding current: |
| 128 // (i) ToNumber if the last puts a number in the accumulator. | 128 // (i) ToNumber if the last puts a number in the accumulator. |
| 129 return false; | 129 return current->bytecode() == Bytecode::kNop; |
|
rmcilroy
2016/07/04 12:35:32
Can we do this in a separate CL please, so we can
oth
2016/07/04 14:56:24
Done.
| |
| 130 } | 130 } |
| 131 } | 131 } |
| 132 | 132 |
| 133 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( | 133 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( |
| 134 const BytecodeNode* const current) const { | 134 const BytecodeNode* const current) const { |
| 135 // | 135 // |
| 136 // The rules for allowing the elision of the last bytecode based | 136 // The rules for allowing the elision of the last bytecode based |
| 137 // on source position are: | 137 // on source position are: |
| 138 // | 138 // |
| 139 // C U R R E N T | 139 // C U R R E N T |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 181 // Star R ====/ Ldar R | 181 // Star R ====/ Ldar R |
| 182 // | 182 // |
| 183 // which loads a global value into both a register and the | 183 // which loads a global value into both a register and the |
| 184 // accumulator. However, in the second form the Ldar can often be | 184 // accumulator. However, in the second form the Ldar can often be |
| 185 // peephole optimized away unlike the Star in the first form. | 185 // peephole optimized away unlike the Star in the first form. |
| 186 // | 186 // |
| 187 last->Transform(new_bytecode, current->operand(0)); | 187 last->Transform(new_bytecode, current->operand(0)); |
| 188 current->set_bytecode(Bytecode::kLdar, current->operand(0)); | 188 current->set_bytecode(Bytecode::kLdar, current->operand(0)); |
| 189 } | 189 } |
| 190 | 190 |
| 191 void TransformToBinaryOpWithSmiOnRhs(Bytecode new_bytecode, | |
| 192 BytecodeNode* const last, | |
| 193 BytecodeNode* const current) { | |
| 194 uint32_t smi_operand = last->operand(0); | |
| 195 current->set_bytecode(new_bytecode, smi_operand, current->operand(0)); | |
| 196 if (last->source_info().is_valid()) { | |
| 197 current->source_info().Clone(last->source_info()); | |
| 198 } | |
| 199 } | |
| 200 | |
| 191 } // namespace | 201 } // namespace |
| 192 | 202 |
| 193 bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes( | 203 bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes( |
| 194 BytecodeNode* const current) { | 204 BytecodeNode* const current) { |
| 195 if (current->bytecode() == Bytecode::kStar && | 205 if (current->bytecode() == Bytecode::kStar && |
| 196 !current->source_info().is_statement()) { | 206 !current->source_info().is_statement()) { |
| 197 // Note: If the Star is tagged with a statement position, we can't | 207 // Note: If the Star is tagged with a statement position, we can't |
| 198 // perform this transform as the store to the register will | 208 // perform this transform as the store to the register will |
| 199 // have the wrong ordering for stepping in the debugger. | 209 // have the wrong ordering for stepping in the debugger. |
| 200 switch (last_.bytecode()) { | 210 switch (last_.bytecode()) { |
| 201 case Bytecode::kLdaNamedProperty: | 211 case Bytecode::kLdaNamedProperty: |
| 202 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current); | 212 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current); |
| 203 return true; | 213 return true; |
| 204 case Bytecode::kLdaKeyedProperty: | 214 case Bytecode::kLdaKeyedProperty: |
| 205 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current); | 215 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current); |
| 206 return true; | 216 return true; |
| 207 case Bytecode::kLdaGlobal: | 217 case Bytecode::kLdaGlobal: |
| 208 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current); | 218 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current); |
| 209 return true; | 219 return true; |
| 210 case Bytecode::kLdaContextSlot: | 220 case Bytecode::kLdaContextSlot: |
| 211 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current); | 221 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current); |
| 212 return true; | 222 return true; |
| 213 case Bytecode::kLdaUndefined: | 223 case Bytecode::kLdaUndefined: |
| 214 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current); | 224 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current); |
| 215 return true; | 225 return true; |
| 216 default: | 226 default: |
| 217 break; | 227 break; |
| 218 } | 228 } |
| 229 } else if (last_.bytecode() == Bytecode::kLdaSmi && | |
| 230 (!last_.source_info().is_valid() || | |
| 231 !current->source_info().is_valid())) { | |
| 232 switch (current->bytecode()) { | |
| 233 case Bytecode::kAdd: | |
| 234 TransformToBinaryOpWithSmiOnRhs(Bytecode::kAddSmi, &last_, current); | |
| 235 InvalidateLast(); | |
| 236 return true; | |
| 237 case Bytecode::kSub: | |
| 238 TransformToBinaryOpWithSmiOnRhs(Bytecode::kSubSmi, &last_, current); | |
| 239 InvalidateLast(); | |
| 240 return true; | |
| 241 case Bytecode::kBitwiseOr: | |
| 242 TransformToBinaryOpWithSmiOnRhs(Bytecode::kBitwiseOrSmi, &last_, | |
| 243 current); | |
| 244 InvalidateLast(); | |
| 245 return true; | |
| 246 case Bytecode::kBitwiseAnd: | |
| 247 TransformToBinaryOpWithSmiOnRhs(Bytecode::kBitwiseAndSmi, &last_, | |
| 248 current); | |
| 249 InvalidateLast(); | |
| 250 return true; | |
| 251 case Bytecode::kShiftLeft: | |
| 252 TransformToBinaryOpWithSmiOnRhs(Bytecode::kShiftLeftSmi, &last_, | |
| 253 current); | |
| 254 InvalidateLast(); | |
| 255 return true; | |
| 256 case Bytecode::kShiftRight: | |
| 257 TransformToBinaryOpWithSmiOnRhs(Bytecode::kShiftRightSmi, &last_, | |
| 258 current); | |
| 259 InvalidateLast(); | |
| 260 return true; | |
| 261 default: | |
| 262 break; | |
| 263 } | |
| 264 } else if (last_.bytecode() == Bytecode::kLdaZero && | |
|
rmcilroy
2016/07/04 12:35:32
Can we not also do the LdaZero optimization for al
oth
2016/07/04 14:56:24
Done. This was skipped due to low numbers of occur
| |
| 265 current->bytecode() == Bytecode::kBitwiseOr && | |
| 266 !current->source_info().is_valid()) { | |
| 267 current->set_bytecode(Bytecode::kBitwiseOrSmi, 0, current->operand(0)); | |
| 268 current->source_info().Clone(last_.source_info()); | |
| 269 InvalidateLast(); | |
| 270 return true; | |
| 219 } | 271 } |
| 272 | |
| 220 return false; | 273 return false; |
| 221 } | 274 } |
| 222 | 275 |
| 223 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump( | 276 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump( |
| 224 BytecodeNode* const current) { | 277 BytecodeNode* const current) { |
| 225 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) && | 278 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) && |
| 226 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); | 279 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); |
| 227 if (can_remove) { | 280 if (can_remove) { |
| 228 // Conditional jumps with boolean conditions are emiitted in | 281 // Conditional jumps with boolean conditions are emiitted in |
| 229 // ToBoolean form by the bytecode array builder, | 282 // ToBoolean form by the bytecode array builder, |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 272 // The current instruction clobbers the accumulator without reading it. The | 325 // The current instruction clobbers the accumulator without reading it. The |
| 273 // load in the last instruction can be elided as it has no effect. | 326 // load in the last instruction can be elided as it has no effect. |
| 274 return true; | 327 return true; |
| 275 } else { | 328 } else { |
| 276 return false; | 329 return false; |
| 277 } | 330 } |
| 278 } | 331 } |
| 279 | 332 |
| 280 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { | 333 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { |
| 281 TryToRemoveLastExpressionPosition(current); | 334 TryToRemoveLastExpressionPosition(current); |
| 282 | |
| 283 if (TransformCurrentBytecode(current) || | 335 if (TransformCurrentBytecode(current) || |
| 284 TransformLastAndCurrentBytecodes(current)) { | 336 TransformLastAndCurrentBytecodes(current)) { |
| 285 return current; | 337 return current; |
| 286 } | 338 } |
| 287 | 339 |
| 288 if (CanElideCurrent(current)) { | 340 if (CanElideCurrent(current)) { |
| 289 if (current->source_info().is_valid()) { | 341 if (current->source_info().is_valid()) { |
| 290 // Preserve the source information by replacing the current bytecode | 342 // Preserve the source information by replacing the current bytecode |
| 291 // with a no op bytecode. | 343 // with a no op bytecode. |
| 292 current->set_bytecode(Bytecode::kNop); | 344 current->set_bytecode(Bytecode::kNop); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 318 next_stage_->Write(&last_); | 370 next_stage_->Write(&last_); |
| 319 InvalidateLast(); | 371 InvalidateLast(); |
| 320 } | 372 } |
| 321 } | 373 } |
| 322 return current; | 374 return current; |
| 323 } | 375 } |
| 324 | 376 |
| 325 } // namespace interpreter | 377 } // namespace interpreter |
| 326 } // namespace internal | 378 } // namespace internal |
| 327 } // namespace v8 | 379 } // namespace v8 |
| OLD | NEW |