| 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 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 // values. Only the first bytecode is needed if there's a sequence | 118 // values. Only the first bytecode is needed if there's a sequence |
| 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) current is Nop. |
| 129 // (ii) ToNumber if the last puts a number in the accumulator. |
| 129 return false; | 130 return false; |
| 130 } | 131 } |
| 131 } | 132 } |
| 132 | 133 |
| 133 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( | 134 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( |
| 134 const BytecodeNode* const current) const { | 135 const BytecodeNode* const current) const { |
| 135 // | 136 // |
| 136 // The rules for allowing the elision of the last bytecode based | 137 // The rules for allowing the elision of the last bytecode based |
| 137 // on source position are: | 138 // on source position are: |
| 138 // | 139 // |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 181 // Star R ====/ Ldar R | 182 // Star R ====/ Ldar R |
| 182 // | 183 // |
| 183 // which loads a global value into both a register and the | 184 // which loads a global value into both a register and the |
| 184 // accumulator. However, in the second form the Ldar can often be | 185 // accumulator. However, in the second form the Ldar can often be |
| 185 // peephole optimized away unlike the Star in the first form. | 186 // peephole optimized away unlike the Star in the first form. |
| 186 // | 187 // |
| 187 last->Transform(new_bytecode, current->operand(0)); | 188 last->Transform(new_bytecode, current->operand(0)); |
| 188 current->set_bytecode(Bytecode::kLdar, current->operand(0)); | 189 current->set_bytecode(Bytecode::kLdar, current->operand(0)); |
| 189 } | 190 } |
| 190 | 191 |
| 192 void TransformToBinaryOpWithSmiOnRhs(Bytecode new_bytecode, |
| 193 BytecodeNode* const last, |
| 194 BytecodeNode* const current) { |
| 195 DCHECK(Bytecodes::IsLdaSmiOrLdaZero(last->bytecode())); |
| 196 uint32_t imm_operand = |
| 197 last->bytecode() == Bytecode::kLdaSmi ? last->operand(0) : 0; |
| 198 current->set_bytecode(new_bytecode, imm_operand, current->operand(0)); |
| 199 if (last->source_info().is_valid()) { |
| 200 current->source_info().Clone(last->source_info()); |
| 201 } |
| 202 } |
| 203 |
| 191 } // namespace | 204 } // namespace |
| 192 | 205 |
| 193 bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes( | 206 bool BytecodePeepholeOptimizer::TransformLastAndCurrentBytecodes( |
| 194 BytecodeNode* const current) { | 207 BytecodeNode* const current) { |
| 195 if (current->bytecode() == Bytecode::kStar && | 208 if (current->bytecode() == Bytecode::kStar && |
| 196 !current->source_info().is_statement()) { | 209 !current->source_info().is_statement()) { |
| 197 // Note: If the Star is tagged with a statement position, we can't | 210 // Note: If the Star is tagged with a statement position, we can't |
| 198 // perform this transform as the store to the register will | 211 // perform this transform as the store to the register will |
| 199 // have the wrong ordering for stepping in the debugger. | 212 // have the wrong ordering for stepping in the debugger. |
| 200 switch (last_.bytecode()) { | 213 switch (last_.bytecode()) { |
| 201 case Bytecode::kLdaNamedProperty: | 214 case Bytecode::kLdaNamedProperty: |
| 202 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current); | 215 TransformLdaStarToLdrLdar(Bytecode::kLdrNamedProperty, &last_, current); |
| 203 return true; | 216 return true; |
| 204 case Bytecode::kLdaKeyedProperty: | 217 case Bytecode::kLdaKeyedProperty: |
| 205 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current); | 218 TransformLdaStarToLdrLdar(Bytecode::kLdrKeyedProperty, &last_, current); |
| 206 return true; | 219 return true; |
| 207 case Bytecode::kLdaGlobal: | 220 case Bytecode::kLdaGlobal: |
| 208 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current); | 221 TransformLdaStarToLdrLdar(Bytecode::kLdrGlobal, &last_, current); |
| 209 return true; | 222 return true; |
| 210 case Bytecode::kLdaContextSlot: | 223 case Bytecode::kLdaContextSlot: |
| 211 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current); | 224 TransformLdaStarToLdrLdar(Bytecode::kLdrContextSlot, &last_, current); |
| 212 return true; | 225 return true; |
| 213 case Bytecode::kLdaUndefined: | 226 case Bytecode::kLdaUndefined: |
| 214 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current); | 227 TransformLdaStarToLdrLdar(Bytecode::kLdrUndefined, &last_, current); |
| 215 return true; | 228 return true; |
| 216 default: | 229 default: |
| 217 break; | 230 break; |
| 218 } | 231 } |
| 232 } else if (Bytecodes::IsLdaSmiOrLdaZero(last_.bytecode()) && |
| 233 (!last_.source_info().is_valid() || |
| 234 !current->source_info().is_valid())) { |
| 235 switch (current->bytecode()) { |
| 236 case Bytecode::kAdd: |
| 237 TransformToBinaryOpWithSmiOnRhs(Bytecode::kAddSmi, &last_, current); |
| 238 InvalidateLast(); |
| 239 return true; |
| 240 case Bytecode::kSub: |
| 241 TransformToBinaryOpWithSmiOnRhs(Bytecode::kSubSmi, &last_, current); |
| 242 InvalidateLast(); |
| 243 return true; |
| 244 case Bytecode::kBitwiseOr: |
| 245 TransformToBinaryOpWithSmiOnRhs(Bytecode::kBitwiseOrSmi, &last_, |
| 246 current); |
| 247 InvalidateLast(); |
| 248 return true; |
| 249 case Bytecode::kBitwiseAnd: |
| 250 TransformToBinaryOpWithSmiOnRhs(Bytecode::kBitwiseAndSmi, &last_, |
| 251 current); |
| 252 InvalidateLast(); |
| 253 return true; |
| 254 case Bytecode::kShiftLeft: |
| 255 TransformToBinaryOpWithSmiOnRhs(Bytecode::kShiftLeftSmi, &last_, |
| 256 current); |
| 257 InvalidateLast(); |
| 258 return true; |
| 259 case Bytecode::kShiftRight: |
| 260 TransformToBinaryOpWithSmiOnRhs(Bytecode::kShiftRightSmi, &last_, |
| 261 current); |
| 262 InvalidateLast(); |
| 263 return true; |
| 264 default: |
| 265 break; |
| 266 } |
| 219 } | 267 } |
| 268 |
| 220 return false; | 269 return false; |
| 221 } | 270 } |
| 222 | 271 |
| 223 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump( | 272 bool BytecodePeepholeOptimizer::RemoveToBooleanFromJump( |
| 224 BytecodeNode* const current) { | 273 BytecodeNode* const current) { |
| 225 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) && | 274 bool can_remove = Bytecodes::IsJumpIfToBoolean(current->bytecode()) && |
| 226 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); | 275 Bytecodes::WritesBooleanToAccumulator(last_.bytecode()); |
| 227 if (can_remove) { | 276 if (can_remove) { |
| 228 // Conditional jumps with boolean conditions are emiitted in | 277 // Conditional jumps with boolean conditions are emiitted in |
| 229 // ToBoolean form by the bytecode array builder, | 278 // 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 | 321 // The current instruction clobbers the accumulator without reading it. The |
| 273 // load in the last instruction can be elided as it has no effect. | 322 // load in the last instruction can be elided as it has no effect. |
| 274 return true; | 323 return true; |
| 275 } else { | 324 } else { |
| 276 return false; | 325 return false; |
| 277 } | 326 } |
| 278 } | 327 } |
| 279 | 328 |
| 280 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { | 329 BytecodeNode* BytecodePeepholeOptimizer::Optimize(BytecodeNode* current) { |
| 281 TryToRemoveLastExpressionPosition(current); | 330 TryToRemoveLastExpressionPosition(current); |
| 282 | |
| 283 if (TransformCurrentBytecode(current) || | 331 if (TransformCurrentBytecode(current) || |
| 284 TransformLastAndCurrentBytecodes(current)) { | 332 TransformLastAndCurrentBytecodes(current)) { |
| 285 return current; | 333 return current; |
| 286 } | 334 } |
| 287 | 335 |
| 288 if (CanElideCurrent(current)) { | 336 if (CanElideCurrent(current)) { |
| 289 if (current->source_info().is_valid()) { | 337 if (current->source_info().is_valid()) { |
| 290 // Preserve the source information by replacing the current bytecode | 338 // Preserve the source information by replacing the current bytecode |
| 291 // with a no op bytecode. | 339 // with a no op bytecode. |
| 292 current->set_bytecode(Bytecode::kNop); | 340 current->set_bytecode(Bytecode::kNop); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 318 next_stage_->Write(&last_); | 366 next_stage_->Write(&last_); |
| 319 InvalidateLast(); | 367 InvalidateLast(); |
| 320 } | 368 } |
| 321 } | 369 } |
| 322 return current; | 370 return current; |
| 323 } | 371 } |
| 324 | 372 |
| 325 } // namespace interpreter | 373 } // namespace interpreter |
| 326 } // namespace internal | 374 } // namespace internal |
| 327 } // namespace v8 | 375 } // namespace v8 |
| OLD | NEW |