| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/objects-inl.h" | 7 #include "src/objects-inl.h" |
| 8 #include "src/objects.h" | 8 #include "src/objects.h" |
| 9 | 9 |
| 10 namespace v8 { | 10 namespace v8 { |
| 11 namespace internal { | 11 namespace internal { |
| 12 namespace interpreter { | 12 namespace interpreter { |
| 13 | 13 |
| 14 BytecodePeepholeOptimizer::BytecodePeepholeOptimizer( | 14 BytecodePeepholeOptimizer::BytecodePeepholeOptimizer( |
| 15 BytecodePipelineStage* next_stage) | 15 BytecodePipelineStage* next_stage) |
| 16 : next_stage_(next_stage), last_(Bytecode::kIllegal) { | 16 : next_stage_(next_stage), last_(Bytecode::kIllegal, BytecodeSourceInfo()) { |
| 17 InvalidateLast(); | 17 InvalidateLast(); |
| 18 } | 18 } |
| 19 | 19 |
| 20 // override | 20 // override |
| 21 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray( | 21 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray( |
| 22 Isolate* isolate, int register_count, int parameter_count, | 22 Isolate* isolate, int register_count, int parameter_count, |
| 23 Handle<FixedArray> handler_table) { | 23 Handle<FixedArray> handler_table) { |
| 24 Flush(); | 24 Flush(); |
| 25 return next_stage_->ToBytecodeArray(isolate, register_count, parameter_count, | 25 return next_stage_->ToBytecodeArray(isolate, register_count, parameter_count, |
| 26 handler_table); | 26 handler_table); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 | 70 |
| 71 bool BytecodePeepholeOptimizer::LastIsValid() const { | 71 bool BytecodePeepholeOptimizer::LastIsValid() const { |
| 72 return last_.bytecode() != Bytecode::kIllegal; | 72 return last_.bytecode() != Bytecode::kIllegal; |
| 73 } | 73 } |
| 74 | 74 |
| 75 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { | 75 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { |
| 76 // An action shouldn't leave a NOP as last bytecode unless it has | 76 // An action shouldn't leave a NOP as last bytecode unless it has |
| 77 // source position information. NOP without source information can | 77 // source position information. NOP without source information can |
| 78 // always be elided. | 78 // always be elided. |
| 79 DCHECK(node->bytecode() != Bytecode::kNop || node->source_info().is_valid()); | 79 DCHECK(node->bytecode() != Bytecode::kNop || node->source_info().is_valid()); |
| 80 | 80 last_ = *node; |
| 81 last_.Clone(node); | |
| 82 } | 81 } |
| 83 | 82 |
| 84 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( | 83 bool BytecodePeepholeOptimizer::CanElideLastBasedOnSourcePosition( |
| 85 const BytecodeNode* const current) const { | 84 const BytecodeNode* const current) const { |
| 86 // | 85 // |
| 87 // The rules for allowing the elision of the last bytecode based | 86 // The rules for allowing the elision of the last bytecode based |
| 88 // on source position are: | 87 // on source position are: |
| 89 // | 88 // |
| 90 // C U R R E N T | 89 // C U R R E N T |
| 91 // +--------+--------+--------+ | 90 // +--------+--------+--------+ |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 135 current->set_bytecode(Bytecode::kLdar, current->operand(0)); | 134 current->set_bytecode(Bytecode::kLdar, current->operand(0)); |
| 136 } | 135 } |
| 137 | 136 |
| 138 void TransformLdaSmiBinaryOpToBinaryOpWithSmi(Bytecode new_bytecode, | 137 void TransformLdaSmiBinaryOpToBinaryOpWithSmi(Bytecode new_bytecode, |
| 139 BytecodeNode* const last, | 138 BytecodeNode* const last, |
| 140 BytecodeNode* const current) { | 139 BytecodeNode* const current) { |
| 141 DCHECK_EQ(last->bytecode(), Bytecode::kLdaSmi); | 140 DCHECK_EQ(last->bytecode(), Bytecode::kLdaSmi); |
| 142 current->set_bytecode(new_bytecode, last->operand(0), current->operand(0), | 141 current->set_bytecode(new_bytecode, last->operand(0), current->operand(0), |
| 143 current->operand(1)); | 142 current->operand(1)); |
| 144 if (last->source_info().is_valid()) { | 143 if (last->source_info().is_valid()) { |
| 145 current->source_info_ptr()->Clone(last->source_info()); | 144 current->set_source_info(last->source_info()); |
| 146 } | 145 } |
| 147 } | 146 } |
| 148 | 147 |
| 149 void TransformLdaZeroBinaryOpToBinaryOpWithZero(Bytecode new_bytecode, | 148 void TransformLdaZeroBinaryOpToBinaryOpWithZero(Bytecode new_bytecode, |
| 150 BytecodeNode* const last, | 149 BytecodeNode* const last, |
| 151 BytecodeNode* const current) { | 150 BytecodeNode* const current) { |
| 152 DCHECK_EQ(last->bytecode(), Bytecode::kLdaZero); | 151 DCHECK_EQ(last->bytecode(), Bytecode::kLdaZero); |
| 153 current->set_bytecode(new_bytecode, 0, current->operand(0), | 152 current->set_bytecode(new_bytecode, 0, current->operand(0), |
| 154 current->operand(1)); | 153 current->operand(1)); |
| 155 if (last->source_info().is_valid()) { | 154 if (last->source_info().is_valid()) { |
| 156 current->source_info_ptr()->Clone(last->source_info()); | 155 current->set_source_info(last->source_info()); |
| 157 } | 156 } |
| 158 } | 157 } |
| 159 | 158 |
| 160 } // namespace | 159 } // namespace |
| 161 | 160 |
| 162 void BytecodePeepholeOptimizer::DefaultAction( | 161 void BytecodePeepholeOptimizer::DefaultAction( |
| 163 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 162 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 164 DCHECK(LastIsValid()); | 163 DCHECK(LastIsValid()); |
| 165 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 164 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 166 | 165 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 void BytecodePeepholeOptimizer::ElideLastAction( | 215 void BytecodePeepholeOptimizer::ElideLastAction( |
| 217 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 216 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 218 DCHECK(LastIsValid()); | 217 DCHECK(LastIsValid()); |
| 219 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 218 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 220 | 219 |
| 221 if (CanElideLastBasedOnSourcePosition(node)) { | 220 if (CanElideLastBasedOnSourcePosition(node)) { |
| 222 if (last()->source_info().is_valid()) { | 221 if (last()->source_info().is_valid()) { |
| 223 // |node| can not have a valid source position if the source | 222 // |node| can not have a valid source position if the source |
| 224 // position of last() is valid (per rules in | 223 // position of last() is valid (per rules in |
| 225 // CanElideLastBasedOnSourcePosition()). | 224 // CanElideLastBasedOnSourcePosition()). |
| 226 node->source_info_ptr()->Clone(last()->source_info()); | 225 node->set_source_info(last()->source_info()); |
| 227 } | 226 } |
| 228 SetLast(node); | 227 SetLast(node); |
| 229 } else { | 228 } else { |
| 230 DefaultAction(node); | 229 DefaultAction(node); |
| 231 } | 230 } |
| 232 } | 231 } |
| 233 | 232 |
| 234 void BytecodePeepholeOptimizer::ChangeBytecodeAction( | 233 void BytecodePeepholeOptimizer::ChangeBytecodeAction( |
| 235 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 234 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 236 DCHECK(LastIsValid()); | 235 DCHECK(LastIsValid()); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 } | 306 } |
| 308 | 307 |
| 309 void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction( | 308 void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction( |
| 310 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 309 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 311 DCHECK(LastIsValid()); | 310 DCHECK(LastIsValid()); |
| 312 DCHECK(Bytecodes::IsJump(node->bytecode())); | 311 DCHECK(Bytecodes::IsJump(node->bytecode())); |
| 313 | 312 |
| 314 if (!CanElideLastBasedOnSourcePosition(node)) { | 313 if (!CanElideLastBasedOnSourcePosition(node)) { |
| 315 next_stage()->Write(last()); | 314 next_stage()->Write(last()); |
| 316 } else if (!node->source_info().is_valid()) { | 315 } else if (!node->source_info().is_valid()) { |
| 317 node->source_info_ptr()->Clone(last()->source_info()); | 316 node->set_source_info(last()->source_info()); |
| 318 } | 317 } |
| 319 InvalidateLast(); | 318 InvalidateLast(); |
| 320 } | 319 } |
| 321 | 320 |
| 322 void BytecodePeepholeOptimizer::ApplyPeepholeAction(BytecodeNode* const node) { | 321 void BytecodePeepholeOptimizer::ApplyPeepholeAction(BytecodeNode* const node) { |
| 323 // A single table is used for looking up peephole optimization | 322 // A single table is used for looking up peephole optimization |
| 324 // matches as it is observed to have better performance. This is | 323 // matches as it is observed to have better performance. This is |
| 325 // inspite of the fact that jump bytecodes and non-jump bytecodes | 324 // inspite of the fact that jump bytecodes and non-jump bytecodes |
| 326 // have different processing logic, in particular a jump bytecode | 325 // have different processing logic, in particular a jump bytecode |
| 327 // always needs to emit the jump via WriteJump(). | 326 // always needs to emit the jump via WriteJump(). |
| 328 const PeepholeActionAndData* const action_data = | 327 const PeepholeActionAndData* const action_data = |
| 329 PeepholeActionTable::Lookup(last()->bytecode(), node->bytecode()); | 328 PeepholeActionTable::Lookup(last()->bytecode(), node->bytecode()); |
| 330 switch (action_data->action) { | 329 switch (action_data->action) { |
| 331 #define CASE(Action) \ | 330 #define CASE(Action) \ |
| 332 case PeepholeAction::k##Action: \ | 331 case PeepholeAction::k##Action: \ |
| 333 Action(node, action_data); \ | 332 Action(node, action_data); \ |
| 334 break; | 333 break; |
| 335 PEEPHOLE_ACTION_LIST(CASE) | 334 PEEPHOLE_ACTION_LIST(CASE) |
| 336 #undef CASE | 335 #undef CASE |
| 337 default: | 336 default: |
| 338 UNREACHABLE(); | 337 UNREACHABLE(); |
| 339 break; | 338 break; |
| 340 } | 339 } |
| 341 } | 340 } |
| 342 | 341 |
| 343 } // namespace interpreter | 342 } // namespace interpreter |
| 344 } // namespace internal | 343 } // namespace internal |
| 345 } // namespace v8 | 344 } // namespace v8 |
| OLD | NEW |