| 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, BytecodeSourceInfo()) { | 16 : next_stage_(next_stage), |
| 17 last_(BytecodeNode::Create<Bytecode::kIllegal>()) { |
| 17 InvalidateLast(); | 18 InvalidateLast(); |
| 18 } | 19 } |
| 19 | 20 |
| 20 // override | 21 // override |
| 21 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray( | 22 Handle<BytecodeArray> BytecodePeepholeOptimizer::ToBytecodeArray( |
| 22 Isolate* isolate, int register_count, int parameter_count, | 23 Isolate* isolate, int register_count, int parameter_count, |
| 23 Handle<FixedArray> handler_table) { | 24 Handle<FixedArray> handler_table) { |
| 24 Flush(); | 25 Flush(); |
| 25 return next_stage_->ToBytecodeArray(isolate, register_count, parameter_count, | 26 return next_stage_->ToBytecodeArray(isolate, register_count, parameter_count, |
| 26 handler_table); | 27 handler_table); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 58 } | 59 } |
| 59 | 60 |
| 60 void BytecodePeepholeOptimizer::Flush() { | 61 void BytecodePeepholeOptimizer::Flush() { |
| 61 if (LastIsValid()) { | 62 if (LastIsValid()) { |
| 62 next_stage_->Write(&last_); | 63 next_stage_->Write(&last_); |
| 63 InvalidateLast(); | 64 InvalidateLast(); |
| 64 } | 65 } |
| 65 } | 66 } |
| 66 | 67 |
| 67 void BytecodePeepholeOptimizer::InvalidateLast() { | 68 void BytecodePeepholeOptimizer::InvalidateLast() { |
| 68 last_.set_bytecode(Bytecode::kIllegal); | 69 last_ = BytecodeNode::Create<Bytecode::kIllegal>(); |
| 69 } | 70 } |
| 70 | 71 |
| 71 bool BytecodePeepholeOptimizer::LastIsValid() const { | 72 bool BytecodePeepholeOptimizer::LastIsValid() const { |
| 72 return last_.bytecode() != Bytecode::kIllegal; | 73 return last_.bytecode() != Bytecode::kIllegal; |
| 73 } | 74 } |
| 74 | 75 |
| 75 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { | 76 void BytecodePeepholeOptimizer::SetLast(const BytecodeNode* const node) { |
| 76 // An action shouldn't leave a NOP as last bytecode unless it has | 77 // An action shouldn't leave a NOP as last bytecode unless it has |
| 77 // source position information. NOP without source information can | 78 // source position information. NOP without source information can |
| 78 // always be elided. | 79 // always be elided. |
| (...skipping 30 matching lines...) Expand all Loading... |
| 109 // default, the upstream bytecode generator filters out unneeded | 110 // default, the upstream bytecode generator filters out unneeded |
| 110 // expression position information so there is neglible benefit to | 111 // expression position information so there is neglible benefit to |
| 111 // handling MAYBE specially. Hence MAYBE is treated the same as NO. | 112 // handling MAYBE specially. Hence MAYBE is treated the same as NO. |
| 112 // | 113 // |
| 113 return (!last_.source_info().is_valid() || | 114 return (!last_.source_info().is_valid() || |
| 114 !current->source_info().is_valid()); | 115 !current->source_info().is_valid()); |
| 115 } | 116 } |
| 116 | 117 |
| 117 namespace { | 118 namespace { |
| 118 | 119 |
| 119 void TransformLdaSmiBinaryOpToBinaryOpWithSmi(Bytecode new_bytecode, | 120 BytecodeNode TransformLdaSmiBinaryOpToBinaryOpWithSmi( |
| 120 BytecodeNode* const last, | 121 Bytecode new_bytecode, BytecodeNode* const last, |
| 121 BytecodeNode* const current) { | 122 BytecodeNode* const current) { |
| 122 DCHECK_EQ(last->bytecode(), Bytecode::kLdaSmi); | 123 DCHECK_EQ(last->bytecode(), Bytecode::kLdaSmi); |
| 123 current->set_bytecode(new_bytecode, last->operand(0), current->operand(0), | 124 BytecodeNode node(new_bytecode, last->operand(0), current->operand(0), |
| 124 current->operand(1)); | 125 current->operand(1), current->source_info()); |
| 125 if (last->source_info().is_valid()) { | 126 if (last->source_info().is_valid()) { |
| 126 current->set_source_info(last->source_info()); | 127 node.set_source_info(last->source_info()); |
| 127 } | 128 } |
| 129 return node; |
| 128 } | 130 } |
| 129 | 131 |
| 130 void TransformLdaZeroBinaryOpToBinaryOpWithZero(Bytecode new_bytecode, | 132 BytecodeNode TransformLdaZeroBinaryOpToBinaryOpWithZero( |
| 131 BytecodeNode* const last, | 133 Bytecode new_bytecode, BytecodeNode* const last, |
| 132 BytecodeNode* const current) { | 134 BytecodeNode* const current) { |
| 133 DCHECK_EQ(last->bytecode(), Bytecode::kLdaZero); | 135 DCHECK_EQ(last->bytecode(), Bytecode::kLdaZero); |
| 134 current->set_bytecode(new_bytecode, 0, current->operand(0), | 136 BytecodeNode node(new_bytecode, 0, current->operand(0), current->operand(1), |
| 135 current->operand(1)); | 137 current->source_info()); |
| 136 if (last->source_info().is_valid()) { | 138 if (last->source_info().is_valid()) { |
| 137 current->set_source_info(last->source_info()); | 139 node.set_source_info(last->source_info()); |
| 138 } | 140 } |
| 141 return node; |
| 139 } | 142 } |
| 140 | 143 |
| 141 } // namespace | 144 } // namespace |
| 142 | 145 |
| 143 void BytecodePeepholeOptimizer::DefaultAction( | 146 void BytecodePeepholeOptimizer::DefaultAction( |
| 144 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 147 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 145 DCHECK(LastIsValid()); | 148 DCHECK(LastIsValid()); |
| 146 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 149 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 147 | 150 |
| 148 next_stage()->Write(last()); | 151 next_stage()->Write(last()); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 168 } | 171 } |
| 169 | 172 |
| 170 void BytecodePeepholeOptimizer::ElideCurrentAction( | 173 void BytecodePeepholeOptimizer::ElideCurrentAction( |
| 171 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 174 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 172 DCHECK(LastIsValid()); | 175 DCHECK(LastIsValid()); |
| 173 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 176 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 174 | 177 |
| 175 if (node->source_info().is_valid()) { | 178 if (node->source_info().is_valid()) { |
| 176 // Preserve the source information by replacing the node bytecode | 179 // Preserve the source information by replacing the node bytecode |
| 177 // with a no op bytecode. | 180 // with a no op bytecode. |
| 178 node->set_bytecode(Bytecode::kNop); | 181 BytecodeNode new_node = |
| 179 DefaultAction(node); | 182 BytecodeNode::Create<Bytecode::kNop>(node->source_info()); |
| 183 DefaultAction(&new_node); |
| 180 } else { | 184 } else { |
| 181 // Nothing to do, keep last and wait for next bytecode to pair with it. | 185 // Nothing to do, keep last and wait for next bytecode to pair with it. |
| 182 } | 186 } |
| 183 } | 187 } |
| 184 | 188 |
| 185 void BytecodePeepholeOptimizer::ElideCurrentIfOperand0MatchesAction( | 189 void BytecodePeepholeOptimizer::ElideCurrentIfOperand0MatchesAction( |
| 186 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 190 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 187 DCHECK(LastIsValid()); | 191 DCHECK(LastIsValid()); |
| 188 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 192 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 189 | 193 |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 DefaultAction(node); | 225 DefaultAction(node); |
| 222 } | 226 } |
| 223 | 227 |
| 224 void BytecodePeepholeOptimizer::TransformLdaSmiBinaryOpToBinaryOpWithSmiAction( | 228 void BytecodePeepholeOptimizer::TransformLdaSmiBinaryOpToBinaryOpWithSmiAction( |
| 225 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 229 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 226 DCHECK(LastIsValid()); | 230 DCHECK(LastIsValid()); |
| 227 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 231 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 228 | 232 |
| 229 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { | 233 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { |
| 230 // Fused last and current into current. | 234 // Fused last and current into current. |
| 231 TransformLdaSmiBinaryOpToBinaryOpWithSmi(action_data->bytecode, last(), | 235 BytecodeNode new_node(TransformLdaSmiBinaryOpToBinaryOpWithSmi( |
| 232 node); | 236 action_data->bytecode, last(), node)); |
| 233 SetLast(node); | 237 SetLast(&new_node); |
| 234 } else { | 238 } else { |
| 235 DefaultAction(node); | 239 DefaultAction(node); |
| 236 } | 240 } |
| 237 } | 241 } |
| 238 | 242 |
| 239 void BytecodePeepholeOptimizer:: | 243 void BytecodePeepholeOptimizer:: |
| 240 TransformLdaZeroBinaryOpToBinaryOpWithZeroAction( | 244 TransformLdaZeroBinaryOpToBinaryOpWithZeroAction( |
| 241 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 245 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 242 DCHECK(LastIsValid()); | 246 DCHECK(LastIsValid()); |
| 243 DCHECK(!Bytecodes::IsJump(node->bytecode())); | 247 DCHECK(!Bytecodes::IsJump(node->bytecode())); |
| 244 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { | 248 if (!node->source_info().is_valid() || !last()->source_info().is_valid()) { |
| 245 // Fused last and current into current. | 249 // Fused last and current into current. |
| 246 TransformLdaZeroBinaryOpToBinaryOpWithZero(action_data->bytecode, last(), | 250 BytecodeNode new_node(TransformLdaZeroBinaryOpToBinaryOpWithZero( |
| 247 node); | 251 action_data->bytecode, last(), node)); |
| 248 SetLast(node); | 252 SetLast(&new_node); |
| 249 } else { | 253 } else { |
| 250 DefaultAction(node); | 254 DefaultAction(node); |
| 251 } | 255 } |
| 252 } | 256 } |
| 253 | 257 |
| 254 void BytecodePeepholeOptimizer::DefaultJumpAction( | 258 void BytecodePeepholeOptimizer::DefaultJumpAction( |
| 255 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 259 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 256 DCHECK(LastIsValid()); | 260 DCHECK(LastIsValid()); |
| 257 DCHECK(Bytecodes::IsJump(node->bytecode())); | 261 DCHECK(Bytecodes::IsJump(node->bytecode())); |
| 258 | 262 |
| 259 next_stage()->Write(last()); | 263 next_stage()->Write(last()); |
| 260 InvalidateLast(); | 264 InvalidateLast(); |
| 261 } | 265 } |
| 262 | 266 |
| 263 void BytecodePeepholeOptimizer::UpdateLastJumpAction( | 267 void BytecodePeepholeOptimizer::UpdateLastJumpAction( |
| 264 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 268 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 265 DCHECK(!LastIsValid()); | 269 DCHECK(!LastIsValid()); |
| 266 DCHECK(Bytecodes::IsJump(node->bytecode())); | 270 DCHECK(Bytecodes::IsJump(node->bytecode())); |
| 267 } | 271 } |
| 268 | 272 |
| 269 void BytecodePeepholeOptimizer::ChangeJumpBytecodeAction( | 273 void BytecodePeepholeOptimizer::ChangeJumpBytecodeAction( |
| 270 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 274 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 271 DCHECK(LastIsValid()); | 275 DCHECK(LastIsValid()); |
| 272 DCHECK(Bytecodes::IsJump(node->bytecode())); | 276 DCHECK(Bytecodes::IsJump(node->bytecode())); |
| 273 | 277 |
| 274 next_stage()->Write(last()); | 278 next_stage()->Write(last()); |
| 275 InvalidateLast(); | 279 InvalidateLast(); |
| 276 node->set_bytecode(action_data->bytecode, node->operand(0)); | 280 node->replace_bytecode(action_data->bytecode); |
| 277 } | 281 } |
| 278 | 282 |
| 279 void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction( | 283 void BytecodePeepholeOptimizer::ElideLastBeforeJumpAction( |
| 280 BytecodeNode* const node, const PeepholeActionAndData* action_data) { | 284 BytecodeNode* const node, const PeepholeActionAndData* action_data) { |
| 281 DCHECK(LastIsValid()); | 285 DCHECK(LastIsValid()); |
| 282 DCHECK(Bytecodes::IsJump(node->bytecode())); | 286 DCHECK(Bytecodes::IsJump(node->bytecode())); |
| 283 | 287 |
| 284 if (!CanElideLastBasedOnSourcePosition(node)) { | 288 if (!CanElideLastBasedOnSourcePosition(node)) { |
| 285 next_stage()->Write(last()); | 289 next_stage()->Write(last()); |
| 286 } else if (!node->source_info().is_valid()) { | 290 } else if (!node->source_info().is_valid()) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 306 #undef CASE | 310 #undef CASE |
| 307 default: | 311 default: |
| 308 UNREACHABLE(); | 312 UNREACHABLE(); |
| 309 break; | 313 break; |
| 310 } | 314 } |
| 311 } | 315 } |
| 312 | 316 |
| 313 } // namespace interpreter | 317 } // namespace interpreter |
| 314 } // namespace internal | 318 } // namespace internal |
| 315 } // namespace v8 | 319 } // namespace v8 |
| OLD | NEW |